Merge branch 'segment-api' into audioreactive-prototype
This commit is contained in:
commit
a6f31a577a
6
package-lock.json
generated
6
package-lock.json
generated
@ -2067,9 +2067,9 @@
|
||||
"integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw=="
|
||||
},
|
||||
"terser": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
||||
"integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz",
|
||||
"integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==",
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.6.1",
|
||||
|
@ -263,120 +263,60 @@ writeChunks(
|
||||
name: "PAGE_settings",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=0\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_wifi.htm",
|
||||
name: "PAGE_settings_wifi",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=1\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_leds.htm",
|
||||
name: "PAGE_settings_leds",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=2\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_dmx.htm",
|
||||
name: "PAGE_settings_dmx",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=7\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_ui.htm",
|
||||
name: "PAGE_settings_ui",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=3\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_sync.htm",
|
||||
name: "PAGE_settings_sync",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=4\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_time.htm",
|
||||
name: "PAGE_settings_time",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=5\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_sec.htm",
|
||||
name: "PAGE_settings_sec",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=6\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_um.htm",
|
||||
name: "PAGE_settings_um",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=8\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_2D.htm",
|
||||
name: "PAGE_settings_2D",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=10\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "settings_pin.htm",
|
||||
|
@ -103,25 +103,24 @@ class Animated_Staircase : public Usermod {
|
||||
|
||||
void updateSegments() {
|
||||
mainSegmentId = strip.getMainSegmentId();
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
for (int i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment &seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) {
|
||||
maxSegmentId = i - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= onIndex && i < offIndex) {
|
||||
segments->setOption(SEG_OPTION_ON, 1, i);
|
||||
seg.setOption(SEG_OPTION_ON, true);
|
||||
|
||||
// We may need to copy mode and colors from segment 0 to make sure
|
||||
// changes are propagated even when the config is changed during a wipe
|
||||
// segments->mode = mainsegment.mode;
|
||||
// segments->colors[0] = mainsegment.colors[0];
|
||||
} else {
|
||||
segments->setOption(SEG_OPTION_ON, 0, i);
|
||||
seg.setOption(SEG_OPTION_ON, false);
|
||||
}
|
||||
// Always mark segments as "transitional", we are animating the staircase
|
||||
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, i);
|
||||
seg.setOption(SEG_OPTION_TRANSITIONAL, true);
|
||||
}
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
@ -290,13 +289,13 @@ class Animated_Staircase : public Usermod {
|
||||
}
|
||||
} else {
|
||||
// Restore segment options
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
for (int i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment &seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) {
|
||||
maxSegmentId = i - 1;
|
||||
break;
|
||||
}
|
||||
segments->setOption(SEG_OPTION_ON, 1, i);
|
||||
seg.setOption(SEG_OPTION_ON, true);
|
||||
}
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
DEBUG_PRINTLN(F("Animated Staircase disabled."));
|
||||
|
@ -1,36 +1,60 @@
|
||||
Hello! I have written a v2 usermod for the BME280/BMP280 sensor based on the [existing v1 usermod](https://github.com/Aircoookie/WLED/blob/master/usermods/Wemos_D1_mini%2BWemos32_mini_shield/usermod_bme280.cpp). It is not just a refactor, there are many changes which I made to fit my use case, and I hope they will fit the use cases of others as well! Most notably, this usermod is *just* for the BME280 and does not control a display like in the v1 usermod designed for the WeMos shield.
|
||||
# Usermod BME280
|
||||
This Usermod is designed to read a `BME280` or `BMP280` sensor and output the following:
|
||||
- Temperature
|
||||
- Humidity (`BME280` only)
|
||||
- Pressure
|
||||
- Heat Index (`BME280` only)
|
||||
- Dew Point (`BME280` only)
|
||||
|
||||
- Requires libraries `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280)) and `Wire`. Please add these under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
||||
- Data is published over MQTT so make sure you've enabled the MQTT sync interface.
|
||||
Configuration is all completed via the Usermod menu. There are no settings to set in code! The following settings can be configured in the Usermod Menu:
|
||||
- Temperature Decimals (number of decimal places to output)
|
||||
- Humidity Decimals
|
||||
- Pressure Decimals
|
||||
- Temperature Interval (how many seconds between reads of temperature and humidity)
|
||||
- Pressure Interval
|
||||
- Publish Always (turn off to only publish changes, on to publish whether or not value changed)
|
||||
- Use Celsius (turn off to use Farenheit)
|
||||
- Home Assistant Discovery (turn on to sent MQTT Discovery entries for Home Assistant)
|
||||
- SCL/SDA GPIO Pins
|
||||
|
||||
Dependencies
|
||||
- Libraries
|
||||
- `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280))
|
||||
- `Wire`
|
||||
- These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
||||
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages!
|
||||
|
||||
To enable, compile with `USERMOD_BME280` defined (i.e. `platformio_override.ini`)
|
||||
In addition to outputting via MQTT, you can read the values from the Info Screen on the dashboard page of the device's web interface.
|
||||
|
||||
Methods also exist to read the read/calculated values from other WLED modules through code.
|
||||
- `getTemperatureC()`
|
||||
- `getTemperatureF()`
|
||||
- `getHumidity()`
|
||||
- `getPressure()`
|
||||
- `getDewPointC()`
|
||||
- `getDewPointF()`
|
||||
- `getHeatIndexC()`
|
||||
- `getHeatIndexF()`
|
||||
|
||||
# Complilation
|
||||
|
||||
To enable, compile with `USERMOD_BME280` defined (e.g. in `platformio_override.ini`)
|
||||
```ini
|
||||
[env:usermod_bme280_d1_mini]
|
||||
extends = env:d1_mini
|
||||
build_flags =
|
||||
${common.build_flags_esp8266}
|
||||
-D USERMOD_BME280
|
||||
```
|
||||
or define `USERMOD_BME280` in `my_config.h`
|
||||
```c++
|
||||
#define USERMOD_BME280
|
||||
lib_deps =
|
||||
${esp8266.lib_deps}
|
||||
BME280@~3.0.0
|
||||
Wire
|
||||
```
|
||||
|
||||
Changes include:
|
||||
- Adjustable measure intervals
|
||||
- Temperature and pressure have separate intervals due to pressure not frequently changing at any constant altitude
|
||||
- Adjustment of number of decimal places in published sensor values
|
||||
- Separate adjustment for temperature, humidity and pressure values
|
||||
- Values are rounded to the specified number of decimal places
|
||||
- Pressure measured in units of hPa instead of Pa
|
||||
- Calculation of heat index (apparent temperature) and dew point
|
||||
- These, along with humidity measurements, are disabled if the sensor is a BMP280
|
||||
- 16x oversampling of sensor during measurement
|
||||
- Values are only published if they are different from the previous value
|
||||
- Values are published on startup (continually until the MQTT broker acknowledges a successful publication)
|
||||
|
||||
Adjustments are made through preprocessor definitions at the start of the class definition.
|
||||
|
||||
MQTT topics are as follows:
|
||||
# MQTT
|
||||
MQTT topics are as follows (`<deviceTopic>` is set in MQTT section of Sync Setup menu):
|
||||
Measurement type | MQTT topic
|
||||
--- | ---
|
||||
Temperature | `<deviceTopic>/temperature`
|
||||
@ -38,3 +62,29 @@ Humidity | `<deviceTopic>/humidity`
|
||||
Pressure | `<deviceTopic>/pressure`
|
||||
Heat index | `<deviceTopic>/heat_index`
|
||||
Dew point | `<deviceTopic>/dew_point`
|
||||
|
||||
If you are using Home Assistant, and `Home Assistant Discovery` is turned on, Home Assistant should automatically detect a new device, provided you have the MQTT integration installed. The device is seperate from the main WLED device and will contain sensors for Pressure, Humidity, Temperature, Dew Point and Heat Index.
|
||||
|
||||
# Revision History
|
||||
Jul 2022
|
||||
- Added Home Assistant Discovery
|
||||
- Added API interface to output data
|
||||
- Removed compile-time variables
|
||||
- Added usermod menu interface
|
||||
- Added value outputs to info screen
|
||||
- Updated `readme.md`
|
||||
- Registered usermod
|
||||
- Implemented PinManager for usermod
|
||||
- Implemented reallocation of pins without reboot
|
||||
|
||||
Apr 2021
|
||||
- Added `Publish Always` option
|
||||
|
||||
Dec 2020
|
||||
- Ported to V2 Usermod format
|
||||
- Customisable `measure intervals`
|
||||
- Customisable number of `decimal places` in published sensor values
|
||||
- Pressure measured in units of hPa instead of Pa
|
||||
- Calculation of heat index (apparent temperature) and dew point
|
||||
- `16x oversampling` of sensor during measurement
|
||||
- Values only published if they are different from the previous value
|
@ -1,3 +1,6 @@
|
||||
// force the compiler to show a warning to confirm that this file is included
|
||||
#warning **** Included USERMOD_BME280 version 2.0 ****
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
@ -9,43 +12,30 @@
|
||||
class UsermodBME280 : public Usermod
|
||||
{
|
||||
private:
|
||||
// User-defined configuration
|
||||
#define Celsius // Show temperature mesaurement in Celcius. Comment out for Fahrenheit
|
||||
#define TemperatureDecimals 1 // Number of decimal places in published temperaure values
|
||||
#define HumidityDecimals 2 // Number of decimal places in published humidity values
|
||||
#define PressureDecimals 2 // Number of decimal places in published pressure values
|
||||
#define TemperatureInterval 5 // Interval to measure temperature (and humidity, dew point if available) in seconds
|
||||
#define PressureInterval 300 // Interval to measure pressure in seconds
|
||||
#define PublishAlways 0 // Publish values even when they have not changed
|
||||
|
||||
// Sanity checks
|
||||
#if !defined(TemperatureDecimals) || TemperatureDecimals < 0
|
||||
#define TemperatureDecimals 0
|
||||
#endif
|
||||
#if !defined(HumidityDecimals) || HumidityDecimals < 0
|
||||
#define HumidityDecimals 0
|
||||
#endif
|
||||
#if !defined(PressureDecimals) || PressureDecimals < 0
|
||||
#define PressureDecimals 0
|
||||
#endif
|
||||
#if !defined(TemperatureInterval) || TemperatureInterval < 0
|
||||
#define TemperatureInterval 1
|
||||
#endif
|
||||
#if !defined(PressureInterval) || PressureInterval < 0
|
||||
#define PressureInterval TemperatureInterval
|
||||
#endif
|
||||
#if !defined(PublishAlways)
|
||||
#define PublishAlways 0
|
||||
#endif
|
||||
// NOTE: Do not implement any compile-time variables, anything the user needs to configure
|
||||
// should be configurable from the Usermod menu using the methods below
|
||||
// key settings set via usermod menu
|
||||
unsigned long TemperatureDecimals = 0; // Number of decimal places in published temperaure values
|
||||
unsigned long HumidityDecimals = 0; // Number of decimal places in published humidity values
|
||||
unsigned long PressureDecimals = 0; // Number of decimal places in published pressure values
|
||||
unsigned long TemperatureInterval = 5; // Interval to measure temperature (and humidity, dew point if available) in seconds
|
||||
unsigned long PressureInterval = 300; // Interval to measure pressure in seconds
|
||||
bool PublishAlways = false; // Publish values even when they have not changed
|
||||
bool UseCelsius = true; // Use Celsius for Reporting
|
||||
bool HomeAssistantDiscovery = false; // Publish Home Assistant Device Information
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
#else // ESP8266 boards
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
// set the default pins based on the architecture, these get overridden by Usermod menu settings
|
||||
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
||||
#define HW_PIN_SCL 22
|
||||
#define HW_PIN_SDA 21
|
||||
#else // ESP8266 boards
|
||||
#define HW_PIN_SCL 5
|
||||
#define HW_PIN_SDA 4
|
||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
int8_t ioPin[2] = {HW_PIN_SCL, HW_PIN_SDA}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup()
|
||||
bool initDone = false;
|
||||
|
||||
// BME280 sensor settings
|
||||
BME280I2C::Settings settings{
|
||||
@ -75,6 +65,7 @@ private:
|
||||
float sensorHeatIndex;
|
||||
float sensorDewPoint;
|
||||
float sensorPressure;
|
||||
String tempScale;
|
||||
// Track previous sensor values
|
||||
float lastTemperature;
|
||||
float lastHumidity;
|
||||
@ -82,43 +73,122 @@ private:
|
||||
float lastDewPoint;
|
||||
float lastPressure;
|
||||
|
||||
// MQTT topic strings for publishing Home Assistant discovery topics
|
||||
bool mqttInitialized = false;
|
||||
String mqttTemperatureTopic = "";
|
||||
String mqttHumidityTopic = "";
|
||||
String mqttPressureTopic = "";
|
||||
String mqttHeatIndexTopic = "";
|
||||
String mqttDewPointTopic = "";
|
||||
|
||||
// Store packet IDs of MQTT publications
|
||||
uint16_t mqttTemperaturePub = 0;
|
||||
uint16_t mqttPressurePub = 0;
|
||||
|
||||
// Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Farenheit being set in Usermod Menu)
|
||||
void UpdateBME280Data(int SensorType)
|
||||
{
|
||||
float _temperature, _humidity, _pressure;
|
||||
#ifdef Celsius
|
||||
|
||||
if (UseCelsius) {
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
||||
#else
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||
|
||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||
|
||||
sensorTemperature = _temperature;
|
||||
sensorHumidity = _humidity;
|
||||
sensorPressure = _pressure;
|
||||
tempScale = "°C";
|
||||
if (sensorType == 1)
|
||||
{
|
||||
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||
}
|
||||
} else {
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
|
||||
#endif
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||
|
||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||
|
||||
sensorTemperature = _temperature;
|
||||
sensorHumidity = _humidity;
|
||||
sensorPressure = _pressure;
|
||||
if (sensorType == 1)
|
||||
{
|
||||
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||
sensorTemperature = _temperature;
|
||||
sensorHumidity = _humidity;
|
||||
sensorPressure = _pressure;
|
||||
tempScale = "°F";
|
||||
if (sensorType == 1)
|
||||
{
|
||||
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Procedure to define all MQTT discovery Topics
|
||||
void _mqttInitialize()
|
||||
{
|
||||
mqttTemperatureTopic = String(mqttDeviceTopic) + F("/temperature");
|
||||
mqttPressureTopic = String(mqttDeviceTopic) + F("/pressure");
|
||||
mqttHumidityTopic = String(mqttDeviceTopic) + F("/humidity");
|
||||
mqttHeatIndexTopic = String(mqttDeviceTopic) + F("/heat_index");
|
||||
mqttDewPointTopic = String(mqttDeviceTopic) + F("/dew_point");
|
||||
|
||||
if (HomeAssistantDiscovery) {
|
||||
_createMqttSensor(F("Temperature"), mqttTemperatureTopic, F("temperature"), tempScale);
|
||||
_createMqttSensor(F("Pressure"), mqttPressureTopic, F("pressure"), F("hPa"));
|
||||
_createMqttSensor(F("Humidity"), mqttHumidityTopic, F("humidity"), F("%"));
|
||||
_createMqttSensor(F("HeatIndex"), mqttHeatIndexTopic, F("temperature"), tempScale);
|
||||
_createMqttSensor(F("DewPoint"), mqttDewPointTopic, F("temperature"), tempScale);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
|
||||
{
|
||||
String t = String(F("homeassistant/sensor/")) + mqttClientID + F("/") + name + F("/config");
|
||||
|
||||
StaticJsonDocument<600> doc;
|
||||
|
||||
doc[F("name")] = String(serverDescription) + " " + name;
|
||||
doc[F("state_topic")] = topic;
|
||||
doc[F("unique_id")] = String(mqttClientID) + name;
|
||||
if (unitOfMeasurement != "")
|
||||
doc[F("unit_of_measurement")] = unitOfMeasurement;
|
||||
if (deviceClass != "")
|
||||
doc[F("device_class")] = deviceClass;
|
||||
doc[F("expire_after")] = 1800;
|
||||
|
||||
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||
device[F("name")] = serverDescription;
|
||||
device[F("identifiers")] = "wled-sensor-" + String(mqttClientID);
|
||||
device[F("manufacturer")] = F("WLED");
|
||||
device[F("model")] = F("FOSS");
|
||||
device[F("sw_version")] = versionString;
|
||||
|
||||
String temp;
|
||||
serializeJson(doc, temp);
|
||||
DEBUG_PRINTLN(t);
|
||||
DEBUG_PRINTLN(temp);
|
||||
|
||||
mqtt->publish(t.c_str(), 0, true, temp.c_str());
|
||||
}
|
||||
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
Wire.begin(SDA_PIN, SCL_PIN);
|
||||
bool HW_Pins_Used = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); // note whether architecture-based hardware SCL/SDA pins used
|
||||
PinOwner po = PinOwner::UM_BME280; // defaults to being pinowner for SCL/SDA pins
|
||||
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins
|
||||
if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) { sensorType=0; return; }
|
||||
|
||||
Wire.begin(ioPin[1], ioPin[0]);
|
||||
|
||||
if (!bme.begin())
|
||||
{
|
||||
sensorType = 0;
|
||||
Serial.println("Could not find BME280I2C sensor!");
|
||||
DEBUG_PRINTLN(F("Could not find BME280I2C sensor!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -126,24 +196,25 @@ public:
|
||||
{
|
||||
case BME280::ChipModel_BME280:
|
||||
sensorType = 1;
|
||||
Serial.println("Found BME280 sensor! Success.");
|
||||
DEBUG_PRINTLN(F("Found BME280 sensor! Success."));
|
||||
break;
|
||||
case BME280::ChipModel_BMP280:
|
||||
sensorType = 2;
|
||||
Serial.println("Found BMP280 sensor! No Humidity available.");
|
||||
DEBUG_PRINTLN(F("Found BMP280 sensor! No Humidity available."));
|
||||
break;
|
||||
default:
|
||||
sensorType = 0;
|
||||
Serial.println("Found UNKNOWN sensor! Error!");
|
||||
DEBUG_PRINTLN(F("Found UNKNOWN sensor! Error!"));
|
||||
}
|
||||
}
|
||||
initDone=true;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// BME280 sensor MQTT publishing
|
||||
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
|
||||
if (sensorType != 0 && mqtt != nullptr)
|
||||
if (sensorType != 0 && WLED_MQTT_CONNECTED)
|
||||
{
|
||||
// Timer to fetch new temperature, humidity and pressure data at intervals
|
||||
timer = millis();
|
||||
@ -154,9 +225,15 @@ public:
|
||||
|
||||
UpdateBME280Data(sensorType);
|
||||
|
||||
float temperature = roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||
float temperature = roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
float humidity, heatIndex, dewPoint;
|
||||
|
||||
if (WLED_MQTT_CONNECTED && !mqttInitialized)
|
||||
{
|
||||
_mqttInitialize();
|
||||
mqttInitialized = true;
|
||||
}
|
||||
|
||||
// If temperature has changed since last measure, create string populated with device topic
|
||||
// from the UI and values read from sensor, then publish to broker
|
||||
if (temperature != lastTemperature || PublishAlways)
|
||||
@ -169,25 +246,25 @@ public:
|
||||
|
||||
if (sensorType == 1) // Only if sensor is a BME280
|
||||
{
|
||||
humidity = roundf(sensorHumidity * pow(10, HumidityDecimals)) / pow(10, HumidityDecimals);
|
||||
heatIndex = roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||
dewPoint = roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||
humidity = roundf(sensorHumidity * powf(10, HumidityDecimals)) / powf(10, HumidityDecimals);
|
||||
heatIndex = roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
dewPoint = roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
|
||||
if (humidity != lastHumidity || PublishAlways)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/humidity";
|
||||
String topic = String(mqttDeviceTopic) + F("/humidity");
|
||||
mqtt->publish(topic.c_str(), 0, false, String(humidity, HumidityDecimals).c_str());
|
||||
}
|
||||
|
||||
if (heatIndex != lastHeatIndex || PublishAlways)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/heat_index";
|
||||
String topic = String(mqttDeviceTopic) + F("/heat_index");
|
||||
mqtt->publish(topic.c_str(), 0, false, String(heatIndex, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
if (dewPoint != lastDewPoint || PublishAlways)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/dew_point";
|
||||
String topic = String(mqttDeviceTopic) + F("/dew_point");
|
||||
mqtt->publish(topic.c_str(), 0, false, String(dewPoint, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
@ -201,11 +278,11 @@ public:
|
||||
{
|
||||
lastPressureMeasure = timer;
|
||||
|
||||
float pressure = roundf(sensorPressure * pow(10, PressureDecimals)) / pow(10, PressureDecimals);
|
||||
float pressure = roundf(sensorPressure * powf(10, PressureDecimals)) / powf(10, PressureDecimals);
|
||||
|
||||
if (pressure != lastPressure || PublishAlways)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/pressure";
|
||||
String topic = String(mqttDeviceTopic) + F("/pressure");
|
||||
mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(pressure, PressureDecimals).c_str());
|
||||
}
|
||||
|
||||
@ -213,4 +290,173 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* API calls te enable data exchange between WLED modules
|
||||
*/
|
||||
inline float getTemperatureC() {
|
||||
if (UseCelsius) {
|
||||
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
} else {
|
||||
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||
}
|
||||
|
||||
}
|
||||
inline float getTemperatureF() {
|
||||
if (UseCelsius) {
|
||||
return ((float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||
} else {
|
||||
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
}
|
||||
}
|
||||
inline float getHumidity() {
|
||||
return (float)roundf(sensorHumidity * powf(10, HumidityDecimals));
|
||||
}
|
||||
inline float getPressure() {
|
||||
return (float)roundf(sensorPressure * powf(10, PressureDecimals));
|
||||
}
|
||||
inline float getDewPointC() {
|
||||
if (UseCelsius) {
|
||||
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
} else {
|
||||
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||
}
|
||||
}
|
||||
inline float getDewPointF() {
|
||||
if (UseCelsius) {
|
||||
return ((float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||
} else {
|
||||
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
}
|
||||
}
|
||||
inline float getHeatIndexC() {
|
||||
if (UseCelsius) {
|
||||
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
} else {
|
||||
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||
}
|
||||
}inline float getHeatIndexF() {
|
||||
if (UseCelsius) {
|
||||
return ((float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||
} else {
|
||||
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
// Publish Sensor Information to Info Page
|
||||
void addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
JsonObject user = root[F("u")];
|
||||
if (user.isNull()) user = root.createNestedObject(F("u"));
|
||||
|
||||
if (sensorType==0) //No Sensor
|
||||
{
|
||||
// if we sensor not detected, let the user know
|
||||
JsonArray temperature_json = user.createNestedArray(F("BME/BMP280 Sensor"));
|
||||
temperature_json.add(F("Not Found"));
|
||||
}
|
||||
else if (sensorType==2) //BMP280
|
||||
{
|
||||
|
||||
JsonArray temperature_json = user.createNestedArray(F("Temperature"));
|
||||
JsonArray pressure_json = user.createNestedArray(F("Pressure"));
|
||||
temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)));
|
||||
temperature_json.add(tempScale);
|
||||
pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)));
|
||||
pressure_json.add(F("hPa"));
|
||||
}
|
||||
else if (sensorType==1) //BME280
|
||||
{
|
||||
JsonArray temperature_json = user.createNestedArray(F("Temperature"));
|
||||
JsonArray humidity_json = user.createNestedArray(F("Humidity"));
|
||||
JsonArray pressure_json = user.createNestedArray(F("Pressure"));
|
||||
JsonArray heatindex_json = user.createNestedArray(F("Heat Index"));
|
||||
JsonArray dewpoint_json = user.createNestedArray(F("Dew Point"));
|
||||
temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||
temperature_json.add(tempScale);
|
||||
humidity_json.add(roundf(sensorHumidity * powf(10, HumidityDecimals)));
|
||||
humidity_json.add(F("%"));
|
||||
pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)));
|
||||
pressure_json.add(F("hPa"));
|
||||
heatindex_json.add(roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||
heatindex_json.add(tempScale);
|
||||
dewpoint_json.add(roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||
dewpoint_json.add(tempScale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Save Usermod Config Settings
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(F("BME280/BMP280"));
|
||||
top[F("TemperatureDecimals")] = TemperatureDecimals;
|
||||
top[F("HumidityDecimals")] = HumidityDecimals;
|
||||
top[F("PressureDecimals")] = PressureDecimals;
|
||||
top[F("TemperatureInterval")] = TemperatureInterval;
|
||||
top[F("PressureInterval")] = PressureInterval;
|
||||
top[F("PublishAlways")] = PublishAlways;
|
||||
top[F("UseCelsius")] = UseCelsius;
|
||||
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
||||
JsonArray io_pin = top.createNestedArray(F("pin"));
|
||||
for (byte i=0; i<2; i++) io_pin.add(ioPin[i]);
|
||||
top[F("help4Pins")] = F("SCL,SDA"); // help for Settings page
|
||||
DEBUG_PRINTLN(F("BME280 config saved."));
|
||||
}
|
||||
|
||||
// Read Usermod Config Settings
|
||||
bool readFromConfig(JsonObject& root)
|
||||
{
|
||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||
|
||||
|
||||
int8_t newPin[2]; for (byte i=0; i<2; i++) newPin[i] = ioPin[i]; // prepare to note changed pins
|
||||
|
||||
JsonObject top = root[F("BME280/BMP280")];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINT(F("BME280/BMP280"));
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
return false;
|
||||
}
|
||||
bool configComplete = !top.isNull();
|
||||
|
||||
// A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing
|
||||
configComplete &= getJsonValue(top[F("TemperatureDecimals")], TemperatureDecimals, 1);
|
||||
configComplete &= getJsonValue(top[F("HumidityDecimals")], HumidityDecimals, 0);
|
||||
configComplete &= getJsonValue(top[F("PressureDecimals")], PressureDecimals, 0);
|
||||
configComplete &= getJsonValue(top[F("TemperatureInterval")], TemperatureInterval, 30);
|
||||
configComplete &= getJsonValue(top[F("PressureInterval")], PressureInterval, 30);
|
||||
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
||||
for (byte i=0; i<2; i++) configComplete &= getJsonValue(top[F("pin")][i], newPin[i], ioPin[i]);
|
||||
|
||||
DEBUG_PRINT(FPSTR(F("BME280/BMP280")));
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
// changing parameters from settings page
|
||||
bool pinsChanged = false;
|
||||
for (byte i=0; i<2; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } // check if any pins changed
|
||||
if (pinsChanged) { //if pins changed, deallocate old pins and allocate new ones
|
||||
PinOwner po = PinOwner::UM_BME280;
|
||||
if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||
pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 2, po); // deallocate pins
|
||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||
setup();
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[F("pin")].isNull();
|
||||
}
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_BME280;
|
||||
}
|
||||
};
|
@ -355,7 +355,7 @@ public:
|
||||
// Color in grayscale bitmaps if Segment 1 exists
|
||||
// TODO If secondary and tertiary are black, color all in primary,
|
||||
// else color first three from Seg 1 color slots and last three from Seg 2 color slots
|
||||
WS2812FX::Segment& seg1 = strip.getSegment(tubeSegment);
|
||||
Segment& seg1 = strip.getSegment(tubeSegment);
|
||||
if (seg1.isActive()) {
|
||||
digitColor = strip.getPixelColor(seg1.start + digit);
|
||||
dimming = seg1.opacity;
|
||||
|
@ -63,7 +63,7 @@ class ElekstubeIPSUsermod : public Usermod {
|
||||
if (!toki.isTick()) return;
|
||||
updateLocalTime();
|
||||
|
||||
WS2812FX::Segment& seg1 = strip.getSegment(tfts.tubeSegment);
|
||||
Segment& seg1 = strip.getSegment(tfts.tubeSegment);
|
||||
if (seg1.isActive()) {
|
||||
bool update = false;
|
||||
if (seg1.opacity != lastBri) update = true;
|
||||
|
@ -132,7 +132,7 @@ static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMP
|
||||
static arduinoFFT FFT = arduinoFFT(vReal, vImag, samplesFFT, SAMPLE_RATE);
|
||||
#endif
|
||||
|
||||
static TaskHandle_t FFT_Task;
|
||||
static TaskHandle_t FFT_Task = nullptr;
|
||||
|
||||
float fftAddAvg(int from, int to) {
|
||||
float result = 0.0f;
|
||||
@ -1150,24 +1150,26 @@ class AudioReactive : public Usermod {
|
||||
uiDomString += F("</button>");
|
||||
infoArr.add(uiDomString);
|
||||
|
||||
infoArr = user.createNestedArray(F("Input level"));
|
||||
uiDomString = F("<div class=\"slider\"><div class=\"sliderwrap il\"><input class=\"noslide\" onchange=\"requestJson({");
|
||||
uiDomString += FPSTR(_name);
|
||||
uiDomString += F(":{");
|
||||
uiDomString += FPSTR(_inputLvl);
|
||||
uiDomString += F(":parseInt(this.value)}});\" oninput=\"updateTrail(this);\" max=255 min=0 type=\"range\" value=");
|
||||
uiDomString += inputLevel;
|
||||
uiDomString += F(" /><div class=\"sliderdisplay\"></div></div></div>"); //<output class=\"sliderbubble\"></output>
|
||||
infoArr.add(uiDomString);
|
||||
if (enabled) {
|
||||
infoArr = user.createNestedArray(F("Input level"));
|
||||
uiDomString = F("<div class=\"slider\"><div class=\"sliderwrap il\"><input class=\"noslide\" onchange=\"requestJson({");
|
||||
uiDomString += FPSTR(_name);
|
||||
uiDomString += F(":{");
|
||||
uiDomString += FPSTR(_inputLvl);
|
||||
uiDomString += F(":parseInt(this.value)}});\" oninput=\"updateTrail(this);\" max=255 min=0 type=\"range\" value=");
|
||||
uiDomString += inputLevel;
|
||||
uiDomString += F(" /><div class=\"sliderdisplay\"></div></div></div>"); //<output class=\"sliderbubble\"></output>
|
||||
infoArr.add(uiDomString);
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
infoArr = user.createNestedArray(F("Sampling time"));
|
||||
infoArr.add(sampleTime);
|
||||
infoArr.add("ms");
|
||||
infoArr = user.createNestedArray(F("FFT time"));
|
||||
infoArr.add(fftTime-sampleTime);
|
||||
infoArr.add("ms");
|
||||
#endif
|
||||
#ifdef WLED_DEBUG
|
||||
infoArr = user.createNestedArray(F("Sampling time"));
|
||||
infoArr.add(sampleTime);
|
||||
infoArr.add("ms");
|
||||
infoArr = user.createNestedArray(F("FFT time"));
|
||||
infoArr.add(fftTime-sampleTime);
|
||||
infoArr.add("ms");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1175,12 +1177,15 @@ class AudioReactive : public Usermod {
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
/*
|
||||
void addToJsonState(JsonObject& root)
|
||||
{
|
||||
//root["user0"] = userVar0;
|
||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||
JsonObject usermod = root[FPSTR(_name)];
|
||||
if (usermod.isNull()) {
|
||||
usermod = root.createNestedObject(FPSTR(_name));
|
||||
}
|
||||
usermod["on"] = enabled;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
@ -1264,8 +1269,7 @@ class AudioReactive : public Usermod {
|
||||
|
||||
JsonObject sync = top.createNestedObject("sync");
|
||||
sync[F("port")] = audioSyncPort;
|
||||
sync[F("send")] = (bool) (audioSyncEnabled & 0x01);
|
||||
sync[F("receive")] = (bool) (audioSyncEnabled & 0x02);
|
||||
sync[F("mode")] = audioSyncEnabled;
|
||||
}
|
||||
|
||||
|
||||
@ -1305,13 +1309,8 @@ class AudioReactive : public Usermod {
|
||||
configComplete &= getJsonValue(top["cfg"][F("gain")], sampleGain);
|
||||
configComplete &= getJsonValue(top["cfg"][F("AGC")], soundAgc);
|
||||
|
||||
configComplete &= getJsonValue(top["sync"][F("port")], audioSyncPort);
|
||||
|
||||
bool send = audioSyncEnabled & 0x01;
|
||||
bool receive = audioSyncEnabled & 0x02;
|
||||
configComplete &= getJsonValue(top["sync"][F("send")], send);
|
||||
configComplete &= getJsonValue(top["sync"][F("receive")], receive);
|
||||
audioSyncEnabled = send | (receive << 1);
|
||||
configComplete &= getJsonValue(top["sync"][F("port")], audioSyncPort);
|
||||
configComplete &= getJsonValue(top["sync"][F("mode")], audioSyncEnabled);
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
@ -1331,6 +1330,10 @@ class AudioReactive : public Usermod {
|
||||
oappend(SET_F("addOption(dd,'Normal',1);"));
|
||||
oappend(SET_F("addOption(dd,'Vivid',2);"));
|
||||
oappend(SET_F("addOption(dd,'Lazy',3);"));
|
||||
oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');"));
|
||||
oappend(SET_F("addOption(dd,'Off',0);"));
|
||||
oappend(SET_F("addOption(dd,'Send',1);"));
|
||||
oappend(SET_F("addOption(dd,'Receive',2);"));
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'<i>requires reboot!</i>');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',0,'I2S SD');"));
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',1,'I2S WS');"));
|
||||
|
@ -96,7 +96,7 @@ class StairwayWipeUsermod : public Usermod {
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
WS2812FX::Segment& seg = strip.getSegment(0);
|
||||
Segment& seg = strip.getSegment(0);
|
||||
bool doReverse = (userVar0 == 2);
|
||||
seg.setOption(1, doReverse);
|
||||
|
||||
|
@ -89,7 +89,7 @@ void startWipe()
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
WS2812FX::Segment& seg = strip.getSegment(0);
|
||||
Segment& seg = strip.getSegment(0);
|
||||
bool doReverse = (userVar0 == 2);
|
||||
seg.setOption(1, doReverse);
|
||||
|
||||
|
@ -251,6 +251,7 @@ private:
|
||||
* Sort either the modes or the palettes using quicksort.
|
||||
*/
|
||||
void re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip) {
|
||||
if (!modeNames) return;
|
||||
listBeingSorted = modeNames;
|
||||
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
|
||||
listBeingSorted = nullptr;
|
||||
@ -527,13 +528,13 @@ public:
|
||||
effectCurrent = modes_alpha_indexes[effectCurrentIndex];
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
strip.setMode(i, effectCurrent);
|
||||
}
|
||||
} else {
|
||||
//WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
//Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
strip.setMode(strip.getMainSegmentId(), effectCurrent);
|
||||
}
|
||||
lampUdated();
|
||||
@ -555,13 +556,13 @@ public:
|
||||
effectSpeed = max(min((increase ? effectSpeed+fadeAmount : effectSpeed-fadeAmount), 255), 0);
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
lampUdated();
|
||||
@ -583,13 +584,13 @@ public:
|
||||
effectIntensity = max(min((increase ? effectIntensity+fadeAmount : effectIntensity-fadeAmount), 255), 0);
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
lampUdated();
|
||||
@ -612,22 +613,23 @@ public:
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
uint8_t id = strip.getFirstSelectedSegId();
|
||||
Segment& sid = strip.getSegment(id);
|
||||
switch (par) {
|
||||
case 3: val = strip.getSegment(id).custom3 = max(min((increase ? strip.getSegment(id).custom3+fadeAmount : strip.getSegment(id).custom3-fadeAmount), 255), 0); break;
|
||||
case 2: val = strip.getSegment(id).custom2 = max(min((increase ? strip.getSegment(id).custom2+fadeAmount : strip.getSegment(id).custom2-fadeAmount), 255), 0); break;
|
||||
default: val = strip.getSegment(id).custom1 = max(min((increase ? strip.getSegment(id).custom1+fadeAmount : strip.getSegment(id).custom1-fadeAmount), 255), 0); break;
|
||||
case 3: val = sid.custom3 = max(min((increase ? sid.custom3+fadeAmount : sid.custom3-fadeAmount), 255), 0); break;
|
||||
case 2: val = sid.custom2 = max(min((increase ? sid.custom2+fadeAmount : sid.custom2-fadeAmount), 255), 0); break;
|
||||
default: val = sid.custom1 = max(min((increase ? sid.custom1+fadeAmount : sid.custom1-fadeAmount), 255), 0); break;
|
||||
}
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || i == id) continue;
|
||||
switch (par) {
|
||||
case 3: strip.getSegment(i).custom3 = strip.getSegment(id).custom3; break;
|
||||
case 2: strip.getSegment(i).custom2 = strip.getSegment(id).custom2; break;
|
||||
default: strip.getSegment(i).custom1 = strip.getSegment(id).custom1; break;
|
||||
case 3: seg.custom3 = sid.custom3; break;
|
||||
case 2: seg.custom2 = sid.custom2; break;
|
||||
default: seg.custom1 = sid.custom1; break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getMainSegment();
|
||||
switch (par) {
|
||||
case 3: val = seg.custom3 = max(min((increase ? seg.custom3+fadeAmount : seg.custom3-fadeAmount), 255), 0); break;
|
||||
case 2: val = seg.custom2 = max(min((increase ? seg.custom2+fadeAmount : seg.custom2-fadeAmount), 255), 0); break;
|
||||
@ -656,13 +658,13 @@ public:
|
||||
effectPalette = palettes_alpha_indexes[effectPaletteIndex];
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.palette = effectPalette;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.palette = effectPalette;
|
||||
}
|
||||
lampUdated();
|
||||
@ -685,13 +687,13 @@ public:
|
||||
colorHStoRGB(currentHue1*256, currentSat1, col);
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
lampUdated();
|
||||
@ -714,13 +716,13 @@ public:
|
||||
currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0);
|
||||
colorHStoRGB(currentHue1*256, currentSat1, col);
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
lampUdated();
|
||||
@ -774,13 +776,13 @@ public:
|
||||
#endif
|
||||
currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0);
|
||||
// if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (byte i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.setCCT(currentCCT, i);
|
||||
seg.setCCT(currentCCT);
|
||||
}
|
||||
// } else {
|
||||
// WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
// Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
// seg.setCCT(currentCCT, strip.getMainSegmentId());
|
||||
// }
|
||||
lampUdated();
|
||||
|
@ -27,14 +27,14 @@ saveMacro(1, "&FX=0&R=255&G=255&B=255", false);
|
||||
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||
|
||||
//select first two segments (background color + FX settable)
|
||||
WS2812FX::Segment &seg = strip.getSegment(0);
|
||||
Segment &seg = strip.getSegment(0);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
|
||||
strip.getSegment(0).setOption(0, false);
|
||||
strip.getSegment(0).setOption(2, false);
|
||||
//other segments are text
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
WS2812FX::Segment &seg = strip.getSegment(i);
|
||||
Segment &seg = strip.getSegment(i);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
|
||||
strip.getSegment(i).setOption(0, true);
|
||||
strip.setBrightness(128);
|
||||
@ -50,7 +50,7 @@ void selectWordSegments(bool state)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
//WS2812FX::Segment &seg = strip.getSegment(i);
|
||||
//Segment &seg = strip.getSegment(i);
|
||||
strip.getSegment(i).setOption(0, state);
|
||||
// strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||
//seg.mode = 12;
|
||||
|
3119
wled00/FX.cpp
3119
wled00/FX.cpp
File diff suppressed because it is too large
Load Diff
1313
wled00/FX.h
1313
wled00/FX.h
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,7 @@
|
||||
// but ledmap takes care of that. ledmap is constructed upon initialization
|
||||
// so matrix should disable regular ledmap processing
|
||||
void WS2812FX::setUpMatrix() {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// erase old ledmap, just in case.
|
||||
if (customMappingTable != nullptr) delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
@ -46,7 +47,7 @@ void WS2812FX::setUpMatrix() {
|
||||
|
||||
// safety check
|
||||
if (matrixWidth * matrixHeight > MAX_LEDS) {
|
||||
matrixWidth = getLengthTotal();
|
||||
matrixWidth = _length;
|
||||
matrixHeight = 1;
|
||||
isMatrix = false;
|
||||
return;
|
||||
@ -94,107 +95,113 @@ void WS2812FX::setUpMatrix() {
|
||||
#endif
|
||||
} else {
|
||||
// memory allocation error
|
||||
matrixWidth = getLengthTotal();
|
||||
matrixWidth = _length;
|
||||
matrixHeight = 1;
|
||||
isMatrix = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// not a matrix set up
|
||||
matrixWidth = getLengthTotal();
|
||||
matrixWidth = _length;
|
||||
matrixHeight = 1;
|
||||
}
|
||||
#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 * matrixWidth + x;
|
||||
if (index >= _length) return;
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
busses.setPixelColor(index, col);
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns RGBW values of pixel
|
||||
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint16_t index = (y * matrixWidth + x);
|
||||
if (index >= _length) return 0;
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
return busses.getPixelColor(index);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Segment:: routines
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||
uint16_t IRAM_ATTR WS2812FX::XY(uint16_t x, uint16_t y) {
|
||||
uint16_t width = SEGMENT.virtualWidth(); // segment width in logical pixels
|
||||
uint16_t height = SEGMENT.virtualHeight(); // segment height in logical pixels
|
||||
/*
|
||||
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) {
|
||||
uint16_t t;
|
||||
// swap X & Y if segment transposed
|
||||
t = x; x = y; y = t;
|
||||
// swap width & height if segment transposed
|
||||
t = width; width = height; height = t;
|
||||
}
|
||||
*/
|
||||
uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint16_t width = virtualWidth(); // segment width in logical pixels
|
||||
uint16_t height = virtualHeight(); // segment height in logical pixels
|
||||
return (x%width) + (y%height) * width;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// get2DPixelIndex(x,y,seg) - returns an index of segment pixel in a matrix layout
|
||||
// index still needs to undergo ledmap processing to represent actual physical pixel
|
||||
// matrix is always organized by matrixHeight number of matrixWidth pixels from top to bottom, left to right
|
||||
// so: pixel at get2DPixelIndex(5,6) in a 2D segment with [start=10, stop=19, startY=20, stopY=29 : 10x10 pixels]
|
||||
// corresponds to pixel with logical index of 847 (0 based) if a 2D segment belongs to a 32x32 matrix.
|
||||
// math: (matrixWidth * (startY + y)) + start + x => (32 * (20+6)) + 10 + 5 = 847
|
||||
uint16_t IRAM_ATTR WS2812FX::get2DPixelIndex(uint16_t x, uint16_t y, uint8_t seg) {
|
||||
if (seg == 255) seg = _segment_index;
|
||||
x %= _segments[seg].width(); // just in case constrain x (wrap around)
|
||||
y %= _segments[seg].height(); // just in case constrain y (wrap around)
|
||||
return ((_segments[seg].startY + y) * matrixWidth) + _segments[seg].start + x;
|
||||
}
|
||||
|
||||
void IRAM_ATTR WS2812FX::setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w)
|
||||
void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
if (!isMatrix) return; // not a matrix set-up
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (!strip.isMatrix) return; // not a matrix set-up
|
||||
|
||||
uint8_t _bri_t = strip._bri_t;
|
||||
//uint8_t _bri_t = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0);
|
||||
if (_bri_t < 255) {
|
||||
r = scale8(r, _bri_t);
|
||||
g = scale8(g, _bri_t);
|
||||
b = scale8(b, _bri_t);
|
||||
w = scale8(w, _bri_t);
|
||||
byte r = scale8(R(col), _bri_t);
|
||||
byte g = scale8(G(col), _bri_t);
|
||||
byte b = scale8(B(col), _bri_t);
|
||||
byte w = scale8(W(col), _bri_t);
|
||||
col = RGBW32(r, g, b, w);
|
||||
}
|
||||
uint32_t col = RGBW32(r, g, b, w);
|
||||
|
||||
if (SEGMENT.getOption(SEG_OPTION_REVERSED) ) x = SEGMENT.virtualWidth() - x - 1;
|
||||
if (SEGMENT.getOption(SEG_OPTION_REVERSED_Y)) y = SEGMENT.virtualHeight() - y - 1;
|
||||
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
|
||||
if (getOption(SEG_OPTION_REVERSED) ) x = virtualWidth() - x - 1;
|
||||
if (getOption(SEG_OPTION_REVERSED_Y)) y = virtualHeight() - y - 1;
|
||||
if (getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
|
||||
|
||||
x *= SEGMENT.groupLength(); // expand to physical pixels
|
||||
y *= SEGMENT.groupLength(); // expand to physical pixels
|
||||
if (x >= SEGMENT.width() || y >= SEGMENT.height()) return; // if pixel would fall out of segment just exit
|
||||
x *= groupLength(); // expand to physical pixels
|
||||
y *= groupLength(); // expand to physical pixels
|
||||
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
|
||||
|
||||
for (uint8_t j = 0; j < SEGMENT.grouping; j++) { // groupping vertically
|
||||
for (uint8_t g = 0; g < SEGMENT.grouping; g++) { // groupping horizontally
|
||||
uint16_t index, xX = (x+g), yY = (y+j);
|
||||
if (xX >= SEGMENT.width() || yY >= SEGMENT.height()) continue; // we have reached one dimension's end
|
||||
for (int j = 0; j < grouping; j++) { // groupping vertically
|
||||
for (int g = 0; g < grouping; g++) { // groupping horizontally
|
||||
uint16_t xX = (x+g), yY = (y+j);
|
||||
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
|
||||
|
||||
//if (SEGMENT.getOption(SEG_OPTION_REVERSED) ) xX = SEGMENT.width() - xX - 1;
|
||||
//if (SEGMENT.getOption(SEG_OPTION_REVERSED_Y)) yY = SEGMENT.height() - yY - 1;
|
||||
strip.setPixelColorXY(start + xX, startY + yY, col);
|
||||
|
||||
index = get2DPixelIndex(xX, yY);
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
busses.setPixelColor(index, col);
|
||||
|
||||
if (SEGMENT.getOption(SEG_OPTION_MIRROR)) { //set the corresponding horizontally mirrored pixel
|
||||
//index = get2DPixelIndex(SEGMENT.width() - xX - 1, yY);
|
||||
index = SEGMENT.getOption(SEG_OPTION_TRANSPOSED) ? get2DPixelIndex(xX, SEGMENT.height() - yY - 1) : get2DPixelIndex(SEGMENT.width() - xX - 1, yY);
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
busses.setPixelColor(index, col);
|
||||
if (getOption(SEG_OPTION_MIRROR)) { //set the corresponding horizontally mirrored pixel
|
||||
if (getOption(SEG_OPTION_TRANSPOSED)) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
|
||||
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
|
||||
}
|
||||
if (SEGMENT.getOption(SEG_OPTION_MIRROR_Y)) { //set the corresponding vertically mirrored pixel
|
||||
//index = get2DPixelIndex(xX, SEGMENT.height() - yY - 1);
|
||||
index = SEGMENT.getOption(SEG_OPTION_TRANSPOSED) ? get2DPixelIndex(SEGMENT.width() - xX - 1, yY) : get2DPixelIndex(xX, SEGMENT.height() - yY - 1);
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
busses.setPixelColor(index, col);
|
||||
if (getOption(SEG_OPTION_MIRROR_Y)) { //set the corresponding vertically mirrored pixel
|
||||
if (getOption(SEG_OPTION_TRANSPOSED)) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
|
||||
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
|
||||
}
|
||||
if (SEGMENT.getOption(SEG_OPTION_MIRROR_Y) && SEGMENT.getOption(SEG_OPTION_MIRROR)) { //set the corresponding vertically AND horizontally mirrored pixel
|
||||
index = get2DPixelIndex(SEGMENT.width() - xX - 1, SEGMENT.height() - yY - 1);
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
busses.setPixelColor(index, col);
|
||||
if (getOption(SEG_OPTION_MIRROR_Y) && getOption(SEG_OPTION_MIRROR)) { //set the corresponding vertically AND horizontally mirrored pixel
|
||||
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// anti-aliased version of setPixelColorXY()
|
||||
void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w, bool aa)
|
||||
void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (!strip.isMatrix) return; // not a matrix set-up
|
||||
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
|
||||
float fX = x * (cols-1);
|
||||
float fY = y * (rows-1);
|
||||
@ -213,80 +220,59 @@ void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(float x, float y, byte r, byte g, b
|
||||
uint32_t cXRYB = getPixelColorXY(xR, yB);
|
||||
|
||||
if (xL!=xR && yT!=yB) {
|
||||
// blend TL pixel
|
||||
cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, uint8_t(sqrtf(dL*dT)*255.0f));
|
||||
setPixelColorXY(xL, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT));
|
||||
// blend TR pixel
|
||||
cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, uint8_t(sqrtf(dR*dT)*255.0f));
|
||||
setPixelColorXY(xR, yT, R(cXRYT), G(cXRYT), B(cXRYT), W(cXRYT));
|
||||
// blend BL pixel
|
||||
cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, uint8_t(sqrtf(dL*dB)*255.0f));
|
||||
setPixelColorXY(xL, yB, R(cXLYB), G(cXLYB), B(cXLYB), W(cXLYB));
|
||||
// blend BR pixel
|
||||
cXRYB = color_blend(RGBW32(r,g,b,w), cXRYB, uint8_t(sqrtf(dR*dB)*255.0f));
|
||||
setPixelColorXY(xR, yB, R(cXRYB), G(cXRYB), B(cXRYB), W(cXRYB));
|
||||
setPixelColorXY(xL, yT, color_blend(col, cXLYT, uint8_t(sqrtf(dL*dT)*255.0f))); // blend TL pixel
|
||||
setPixelColorXY(xR, yT, color_blend(col, cXRYT, uint8_t(sqrtf(dR*dT)*255.0f))); // blend TR pixel
|
||||
setPixelColorXY(xL, yB, color_blend(col, cXLYB, uint8_t(sqrtf(dL*dB)*255.0f))); // blend BL pixel
|
||||
setPixelColorXY(xR, yB, color_blend(col, cXRYB, uint8_t(sqrtf(dR*dB)*255.0f))); // blend BR pixel
|
||||
} else if (xR!=xL && yT==yB) {
|
||||
// blend L pixel
|
||||
cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, uint8_t(dL*255.0f));
|
||||
setPixelColorXY(xR, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT));
|
||||
// blend R pixel
|
||||
cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, uint8_t(dR*255.0f));
|
||||
setPixelColorXY(xR, yT, R(cXRYT), G(cXRYT), B(cXRYT), W(cXRYT));
|
||||
setPixelColorXY(xR, yT, color_blend(col, cXLYT, uint8_t(dL*255.0f))); // blend L pixel
|
||||
setPixelColorXY(xR, yT, color_blend(col, cXRYT, uint8_t(dR*255.0f))); // blend R pixel
|
||||
} else if (xR==xL && yT!=yB) {
|
||||
// blend T pixel
|
||||
cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, uint8_t(dT*255.0f));
|
||||
setPixelColorXY(xR, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT));
|
||||
// blend B pixel
|
||||
cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, uint8_t(dB*255.0f));
|
||||
setPixelColorXY(xL, yB, R(cXLYB), G(cXLYB), B(cXLYB), W(cXLYB));
|
||||
setPixelColorXY(xR, yT, color_blend(col, cXLYT, uint8_t(dT*255.0f))); // blend T pixel
|
||||
setPixelColorXY(xL, yB, color_blend(col, cXLYB, uint8_t(dB*255.0f))); // blend B pixel
|
||||
} else {
|
||||
// exact match (x & y land on a pixel)
|
||||
setPixelColorXY(xL, yT, r, g, b, w);
|
||||
setPixelColorXY(xL, yT, col); // exact match (x & y land on a pixel)
|
||||
}
|
||||
} else {
|
||||
setPixelColorXY(uint16_t(roundf(fX)), uint16_t(roundf(fY)), r, g, b, w);
|
||||
setPixelColorXY(uint16_t(roundf(fX)), uint16_t(roundf(fY)), col);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns RGBW values of pixel
|
||||
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
uint16_t index;
|
||||
if (SEGLEN) {
|
||||
if (SEGMENT.getOption(SEG_OPTION_REVERSED) ) x = SEGMENT.virtualWidth() - x - 1;
|
||||
if (SEGMENT.getOption(SEG_OPTION_REVERSED_Y)) y = SEGMENT.virtualHeight() - y - 1;
|
||||
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
|
||||
|
||||
x *= SEGMENT.groupLength(); // expand to physical pixels
|
||||
y *= SEGMENT.groupLength(); // expand to physical pixels
|
||||
if (x >= SEGMENT.width() || y >= SEGMENT.height()) return 0;
|
||||
|
||||
index = get2DPixelIndex(x, y);
|
||||
} else {
|
||||
index = y * matrixWidth + x;
|
||||
}
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
|
||||
return busses.getPixelColor(index);
|
||||
uint32_t Segment::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (getOption(SEG_OPTION_REVERSED) ) x = virtualWidth() - x - 1;
|
||||
if (getOption(SEG_OPTION_REVERSED_Y)) y = virtualHeight() - y - 1;
|
||||
if (getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
|
||||
x *= groupLength(); // expand to physical pixels
|
||||
y *= groupLength(); // expand to physical pixels
|
||||
if (x >= width() || y >= height()) return 0;
|
||||
return strip.getPixelColorXY(start + x, startY + y);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Blends the specified color with the existing pixel color.
|
||||
*/
|
||||
void WS2812FX::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) {
|
||||
// Blends the specified color with the existing pixel color.
|
||||
void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the specified color with the existing pixel color perserving color balance.
|
||||
*/
|
||||
void WS2812FX::addPixelColorXY(uint16_t x, uint16_t y, uint32_t color) {
|
||||
// Adds the specified color with the existing pixel color perserving color balance.
|
||||
void Segment::addPixelColorXY(uint16_t x, uint16_t y, uint32_t color) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color));
|
||||
#endif
|
||||
}
|
||||
|
||||
// blurRow: perform a blur on a row of a rectangular matrix
|
||||
void WS2812FX::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
|
||||
if (row >= rows) return;
|
||||
// blur one row
|
||||
@ -294,13 +280,13 @@ void WS2812FX::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint16_t x = 0; x < cols; x++) {
|
||||
CRGB cur = leds ? leds[XY(x,row)] : col_to_crgb(getPixelColorXY(x, row));
|
||||
CRGB cur = leds ? leds[XY(x,row)] : CRGB(getPixelColorXY(x, row));
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if (x) {
|
||||
CRGB prev = (leds ? leds[XY(x-1,row)] : col_to_crgb(getPixelColorXY(x-1, row))) + part;
|
||||
CRGB prev = (leds ? leds[XY(x-1,row)] : CRGB(getPixelColorXY(x-1, row))) + part;
|
||||
if (leds) leds[XY(x-1,row)] = prev;
|
||||
else setPixelColorXY(x-1, row, prev);
|
||||
}
|
||||
@ -308,12 +294,14 @@ void WS2812FX::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
|
||||
else setPixelColorXY(x, row, cur);
|
||||
carryover = part;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// blurCol: perform a blur on a column of a rectangular matrix
|
||||
void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
|
||||
if (col >= cols) return;
|
||||
// blur one column
|
||||
@ -321,13 +309,13 @@ void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint16_t i = 0; i < rows; i++) {
|
||||
CRGB cur = leds ? leds[XY(col,i)] : col_to_crgb(getPixelColorXY(col, i));
|
||||
CRGB cur = leds ? leds[XY(col,i)] : CRGB(getPixelColorXY(col, i));
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if (i) {
|
||||
CRGB prev = (leds ? leds[XY(col,i-1)] : col_to_crgb(getPixelColorXY(col, i-1))) + part;
|
||||
CRGB prev = (leds ? leds[XY(col,i-1)] : CRGB(getPixelColorXY(col, i-1))) + part;
|
||||
if (leds) leds[XY(col,i-1)] = prev;
|
||||
else setPixelColorXY(col, i-1, prev);
|
||||
}
|
||||
@ -335,6 +323,7 @@ void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
|
||||
else setPixelColorXY(col, i, cur);
|
||||
carryover = part;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
|
||||
@ -351,17 +340,20 @@ void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
|
||||
// eventually all the way to black; this is by design so that
|
||||
// it can be used to (slowly) clear the LEDs to black.
|
||||
|
||||
void WS2812FX::blur1d(CRGB* leds, fract8 blur_amount) {
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::blur1d(CRGB* leds, fract8 blur_amount) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (uint16_t y = 0; y < rows; y++) blurRow(y, blur_amount, leds);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
|
||||
void WS2812FX::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
const uint16_t dim1 = vertical ? rows : cols;
|
||||
const uint16_t dim2 = vertical ? cols : rows;
|
||||
void Segment::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
const uint16_t dim1 = vertical ? rows : cols;
|
||||
const uint16_t dim2 = vertical ? cols : rows;
|
||||
if (i >= dim2) return;
|
||||
const float seep = blur_amount/255.f;
|
||||
const float keep = 3.f - 2.f*seep;
|
||||
@ -374,9 +366,9 @@ void WS2812FX::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds)
|
||||
uint16_t yp = vertical ? y-1 : y;
|
||||
uint16_t xn = vertical ? x : x+1;
|
||||
uint16_t yn = vertical ? y+1 : y;
|
||||
CRGB curr = leds ? leds[XY(x,y)] : col_to_crgb(getPixelColorXY(x,y));
|
||||
CRGB prev = (xp<0 || yp<0) ? CRGB::Black : (leds ? leds[XY(xp,yp)] : col_to_crgb(getPixelColorXY(xp,yp)));
|
||||
CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : (leds ? leds[XY(xn,yn)] : col_to_crgb(getPixelColorXY(xn,yn)));
|
||||
CRGB curr = leds ? leds[XY(x,y)] : CRGB(getPixelColorXY(x,y));
|
||||
CRGB prev = (xp<0 || yp<0) ? CRGB::Black : (leds ? leds[XY(xp,yp)] : CRGB(getPixelColorXY(xp,yp)));
|
||||
CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : (leds ? leds[XY(xn,yn)] : CRGB(getPixelColorXY(xn,yn)));
|
||||
uint16_t r, g, b;
|
||||
r = (curr.r*keep + (prev.r + next.r)*seep) / 3;
|
||||
g = (curr.g*keep + (prev.g + next.g)*seep) / 3;
|
||||
@ -389,63 +381,65 @@ void WS2812FX::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds)
|
||||
if (leds) leds[XY(x,y)] = tmp[j];
|
||||
else setPixelColorXY(x, y, tmp[j]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::blur2d(CRGB* leds, fract8 blur_amount) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::blur2d(CRGB* leds, fract8 blur_amount) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (uint16_t i = 0; i < rows; i++) blurRow(i, blur_amount, leds); // blur all rows
|
||||
for (uint16_t k = 0; k < cols; k++) blurCol(k, blur_amount, leds); // blur all columns
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::moveX(CRGB *leds, int8_t delta) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::moveX(CRGB *leds, int8_t delta) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (!delta) return;
|
||||
if (delta > 0) {
|
||||
for (uint8_t y = 0; y < rows; y++) for (uint8_t x = 0; x < cols-1; x++) {
|
||||
if (x + delta >= cols) break;
|
||||
if (leds) leds[XY(x, y)] = leds[XY((x + delta)%cols, y)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY((x + delta)%cols, y));
|
||||
}
|
||||
} else {
|
||||
for (uint8_t y = 0; y < rows; y++) for (int16_t x = cols-1; x >= 0; x--) {
|
||||
if (x + delta < 0) {
|
||||
if (leds) leds[XY(x, y)] = leds[XY(cols + delta, y)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(cols + delta, y));
|
||||
} else {
|
||||
if (leds) leds[XY(x, y)] = leds[XY(x + delta, y)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(x + delta, y));
|
||||
}
|
||||
if (x + delta < 0) break;
|
||||
if (leds) leds[XY(x, y)] = leds[XY(x + delta, y)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(x + delta, y));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::moveY(CRGB *leds, int8_t delta) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::moveY(CRGB *leds, int8_t delta) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (!delta) return;
|
||||
if (delta > 0) {
|
||||
for (uint8_t x = 0; x < cols; x++) for (uint8_t y = 0; y < rows-1; y++) {
|
||||
if (leds) leds[XY(x, y)] = leds[XY(x, (y + delta)%rows)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(x, (y + delta)%rows));
|
||||
if (y + delta >= rows) break;
|
||||
if (leds) leds[XY(x, y)] = leds[XY(x, (y + delta))];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(x, (y + delta)));
|
||||
}
|
||||
} else {
|
||||
for (uint8_t x = 0; x < cols; x++) for (int16_t y = rows-1; y >= 0; y--) {
|
||||
if (y + delta < 0) {
|
||||
if (leds) leds[XY(x, y)] = leds[XY(x, rows + delta)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(x, rows + delta));
|
||||
} else {
|
||||
if (leds) leds[XY(x, y)] = leds[XY(x, y + delta)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(x, y + delta));
|
||||
}
|
||||
if (y + delta < 0) break;
|
||||
if (leds) leds[XY(x, y)] = leds[XY(x, y + delta)];
|
||||
else setPixelColorXY(x, y, getPixelColorXY(x, y + delta));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// move() - move all pixels in desired direction delta number of pixels
|
||||
// @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down
|
||||
// @param delta number of pixels to move
|
||||
void WS2812FX::move(uint8_t dir, uint8_t delta, CRGB *leds) {
|
||||
void Segment::move(uint8_t dir, uint8_t delta, CRGB *leds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (delta==0) return;
|
||||
switch (dir) {
|
||||
case 0: moveX(leds, delta); break;
|
||||
@ -457,21 +451,25 @@ void WS2812FX::move(uint8_t dir, uint8_t delta, CRGB *leds) {
|
||||
case 6: moveY(leds,-delta); break;
|
||||
case 7: moveX(leds, delta); moveY(leds,-delta); break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::fill_solid(CRGB* leds, CRGB color) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::fill_solid(CRGB* leds, CRGB color) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
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++) {
|
||||
if (leds) leds[XY(x,y)] = color;
|
||||
else setPixelColorXY(x, y, color);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
||||
void WS2812FX::fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (int16_t y = -radius; y <= radius; y++) {
|
||||
for (int16_t x = -radius; x <= radius; x++) {
|
||||
if (x * x + y * y <= radius * radius &&
|
||||
@ -480,31 +478,39 @@ void WS2812FX::fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius,
|
||||
leds[XY(cx + x, cy + y)] += col;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::fadeToBlackBy(CRGB* leds, uint8_t fadeBy) {
|
||||
void Segment::fadeToBlackBy(CRGB* leds, uint8_t fadeBy) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
nscale8(leds, 255 - fadeBy);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::nscale8(CRGB* leds, uint8_t scale) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::nscale8(CRGB* leds, uint8_t scale) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
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++) {
|
||||
if (leds) leds[XY(x,y)].nscale8(scale);
|
||||
else setPixelColorXY(x, y, col_to_crgb(getPixelColorXY(x, y)).nscale8(scale));
|
||||
else setPixelColorXY(x, y, CRGB(getPixelColorXY(x, y)).nscale8(scale));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::setPixels(CRGB* leds) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::setPixels(CRGB* leds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
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++) setPixelColorXY(x, y, leds[XY(x,y)]);
|
||||
#endif
|
||||
}
|
||||
|
||||
//line function
|
||||
void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return;
|
||||
const int16_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
|
||||
const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
|
||||
@ -517,8 +523,10 @@ void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB
|
||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||
if (e2 < dy) { err += dx; y0 += sy; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// font curtesy of https://github.com/idispatch/raster-fonts
|
||||
static const unsigned char console_font_6x8[] PROGMEM = {
|
||||
|
||||
@ -4527,10 +4535,10 @@ static const unsigned char console_font_5x8[] PROGMEM = {
|
||||
0x00, /* 00000 */
|
||||
0x00, /* 00000 */
|
||||
0x90, /* 10010 */
|
||||
0x90, /* 10010 */
|
||||
0xF0, /* 11110 */
|
||||
0x90, /* 10010 */
|
||||
0x90, /* 10010 */
|
||||
0x90, /* 10010 */
|
||||
0x00, /* 00000 */
|
||||
|
||||
/*
|
||||
@ -6669,19 +6677,21 @@ static const unsigned char console_font_5x8[] PROGMEM = {
|
||||
0x00, /* 00000 */
|
||||
0x00, /* 00000 */
|
||||
};
|
||||
#endif
|
||||
|
||||
// draws a raster font character on canvas
|
||||
// only supports 5x8 and 6x8 fonts ATM
|
||||
void WS2812FX::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color, CRGB *leds) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color, CRGB *leds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
|
||||
if (w<5 || w>6 || h!=8) return;
|
||||
for (uint8_t i = 0; i<h; i++) { // character height
|
||||
int16_t y0 = y + i;
|
||||
if (y0 < 0) continue; // drawing off-screen
|
||||
if (y0 >= rows) break; // drawing off-screen
|
||||
uint8_t bits;
|
||||
uint8_t bits = 0;
|
||||
switch (w) {
|
||||
case 5: bits = pgm_read_byte_near(&console_font_5x8[(chr * 8) + i]); break;
|
||||
case 6: bits = pgm_read_byte_near(&console_font_6x8[(chr * 8) + i]); break;
|
||||
@ -6694,10 +6704,12 @@ void WS2812FX::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8))
|
||||
void WS2812FX::wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel procedure by reddit u/sutaburosu
|
||||
void Segment::wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel procedure by reddit u/sutaburosu
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// extract the fractional parts and derive their inverses
|
||||
uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
|
||||
// calculate the intensities for each affected pixel
|
||||
@ -6710,5 +6722,6 @@ void WS2812FX::wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c) { //awe
|
||||
leds[xy].g = qadd8(leds[xy].g, c.g * wu[i] >> 8);
|
||||
leds[xy].b = qadd8(leds[xy].b, c.b * wu[i] >> 8);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#undef WU_WEIGHT
|
||||
|
1656
wled00/FX_fcn.cpp
1656
wled00/FX_fcn.cpp
File diff suppressed because it is too large
Load Diff
@ -195,11 +195,11 @@ void handleAnalog(uint8_t b)
|
||||
colorHStoRGB(aRead*256,255,col);
|
||||
} else {
|
||||
// otherwise use "double press" for segment selection
|
||||
WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]);
|
||||
Segment& seg = strip.getSegment(macroDoublePress[b]);
|
||||
if (aRead == 0) {
|
||||
seg.setOption(SEG_OPTION_ON, 0); // off
|
||||
} else {
|
||||
seg.setOpacity(aRead, macroDoublePress[b]);
|
||||
seg.setOpacity(aRead);
|
||||
seg.setOption(SEG_OPTION_ON, 1);
|
||||
}
|
||||
// this will notify clients of update (websockets,mqtt,etc)
|
||||
|
@ -91,6 +91,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
JsonObject matrix = hw_led[F("matrix")];
|
||||
if (!matrix.isNull()) {
|
||||
@ -125,6 +126,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
strip.setUpMatrix();
|
||||
}
|
||||
#endif
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
|
||||
@ -132,6 +134,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
uint8_t s = 0; // bus iterator
|
||||
if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback
|
||||
uint32_t mem = 0;
|
||||
bool busesChanged = false;
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES) break;
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
@ -161,10 +164,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
} else {
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
|
||||
doInitBusses = true;
|
||||
busesChanged = true;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
doInitBusses = busesChanged;
|
||||
// finalization done in beginStrip()
|
||||
}
|
||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||
@ -618,6 +622,7 @@ void serializeConfig() {
|
||||
hw_led["fps"] = strip.getTargetFps();
|
||||
hw_led[F("rgbwm")] = Bus::getAutoWhiteMode(); // global override
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
if (strip.isMatrix) {
|
||||
JsonObject matrix = hw_led.createNestedObject(F("matrix"));
|
||||
@ -639,6 +644,7 @@ void serializeConfig() {
|
||||
pnl["s"] = strip.panel[i].serpentine;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
|
||||
|
@ -1,12 +1,57 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Color conversion methods
|
||||
* Color conversion & utility methods
|
||||
*/
|
||||
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
uint32_t IRAM_ATTR color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
||||
if(blend == 0) return color1;
|
||||
uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
|
||||
if(blend == blendmax) return color2;
|
||||
uint8_t shift = b16 ? 16 : 8;
|
||||
|
||||
uint32_t w1 = W(color1);
|
||||
uint32_t r1 = R(color1);
|
||||
uint32_t g1 = G(color1);
|
||||
uint32_t b1 = B(color1);
|
||||
|
||||
uint32_t w2 = W(color2);
|
||||
uint32_t r2 = R(color2);
|
||||
uint32_t g2 = G(color2);
|
||||
uint32_t b2 = B(color2);
|
||||
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
|
||||
|
||||
return RGBW32(r3, g3, b3, w3);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
}
|
||||
|
||||
void setRandomColor(byte* rgb)
|
||||
{
|
||||
lastRandomIndex = strip.get_random_wheel_index(lastRandomIndex);
|
||||
lastRandomIndex = strip.getMainSegment().get_random_wheel_index(lastRandomIndex);
|
||||
colorHStoRGB(lastRandomIndex*256,255,rgb);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
* Readability defines and their associated numerical values + compile-time constants
|
||||
*/
|
||||
|
||||
#define GRADIENT_PALETTE_COUNT 58
|
||||
|
||||
//Defaults
|
||||
#define DEFAULT_CLIENT_SSID "Your_Network"
|
||||
#define DEFAULT_AP_PASS "wled1234"
|
||||
@ -76,7 +78,8 @@
|
||||
#define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h"
|
||||
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
||||
#define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h"
|
||||
#define USERMOD_ID_AUDIOREACTIVE 30 //Usermod "audioreactive.h"
|
||||
#define USERMOD_ID_BME280 30 //Usermod "usermod_bme280.h
|
||||
#define USERMOD_ID_AUDIOREACTIVE 31 //Usermod "audioreactive.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@ -223,6 +226,7 @@
|
||||
#define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment
|
||||
#define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor
|
||||
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
|
||||
#define SEG_OPTION_RESET 6 //Segment runtime requires reset
|
||||
#define SEG_OPTION_TRANSITIONAL 7
|
||||
#define SEG_OPTION_REVERSED_Y 8
|
||||
#define SEG_OPTION_MIRROR_Y 9
|
||||
@ -358,4 +362,46 @@
|
||||
|
||||
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
|
||||
|
||||
#if defined(ESP8266) && defined(HW_PIN_SCL)
|
||||
#undef HW_PIN_SCL
|
||||
#endif
|
||||
#if defined(ESP8266) && defined(HW_PIN_SDA)
|
||||
#undef HW_PIN_SDA
|
||||
#endif
|
||||
#ifndef HW_PIN_SCL
|
||||
#ifdef ESP8266
|
||||
#define HW_PIN_SCL 5
|
||||
#else
|
||||
#define HW_PIN_SCL 22
|
||||
#endif
|
||||
#endif
|
||||
#ifndef HW_PIN_SDA
|
||||
#ifdef ESP8266
|
||||
#define HW_PIN_SDA 4
|
||||
#else
|
||||
#define HW_PIN_SDA 21
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266) && defined(HW_PIN_CLOCKSPI)
|
||||
#undef HW_PIN_CLOCKSPI
|
||||
#endif
|
||||
#if defined(ESP8266) && defined(HW_PIN_DATASPI)
|
||||
#undef HW_PIN_DATASPI
|
||||
#endif
|
||||
#ifndef HW_PIN_CLOCKSPI
|
||||
#ifdef ESP8266
|
||||
#define HW_PIN_CLOCKSPI 14
|
||||
#else
|
||||
#define HW_PIN_CLOCKSPI 18
|
||||
#endif
|
||||
#endif
|
||||
#ifndef HW_PIN_DATASPI
|
||||
#ifdef ESP8266
|
||||
#define HW_PIN_DATASPI 13
|
||||
#else
|
||||
#define HW_PIN_DATASPI 23
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -193,7 +193,7 @@ button {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 12px;
|
||||
pointer-events: none;
|
||||
/*pointer-events: none;*/
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
@ -368,7 +368,7 @@ button {
|
||||
}
|
||||
|
||||
#sliders {
|
||||
width: 310px;
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
@ -380,18 +380,34 @@ button {
|
||||
}
|
||||
|
||||
.slider {
|
||||
background: var(--c-2);
|
||||
max-width: 310px;
|
||||
background-color: var(--c-2);
|
||||
max-width: 300px;
|
||||
min-width: 280px;
|
||||
margin: 0 auto; /* add 5px; if you want some vertical space but looks ugly */
|
||||
border-radius: 15px;
|
||||
border-radius: 24px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.filter {
|
||||
background-color: var(--c-4);
|
||||
box-shadow: 0px 0px 6px 6px var(--c-1);
|
||||
border-radius: 26px;
|
||||
height: 26px;
|
||||
margin: 0 auto 4px; /* 8px if you want space */
|
||||
padding: 8px 2px;
|
||||
position: relative;
|
||||
/*width: 260px;*/
|
||||
/*transition: opacity 1s;*/
|
||||
/*opacity: 1;*/
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Tooltip text */
|
||||
.slider .tooltiptext {
|
||||
visibility: hidden;
|
||||
background-color: var(--c-5);
|
||||
/*border: 2px solid var(--c-2);*/
|
||||
box-shadow: 4px 4px 10px 4px var(--c-1);
|
||||
color: var(--c-f);
|
||||
text-align: center;
|
||||
padding: 5px 10px;
|
||||
@ -447,6 +463,10 @@ button {
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
.fade {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 10px;
|
||||
@ -827,19 +847,22 @@ input[type=range]::-moz-range-thumb {
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 4px;
|
||||
padding: 4px 8px;
|
||||
margin: 0;
|
||||
font-size: 19px;
|
||||
background-color: var(--c-3);
|
||||
color: var(--c-d);
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--c-2);
|
||||
border-radius: 5px;
|
||||
border: 0 solid var(--c-2);
|
||||
border-radius: 20px;
|
||||
transition-duration: 0.5s;
|
||||
-webkit-backface-visibility: hidden;
|
||||
-webkit-transform:translate3d(0,0,0);
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
backface-visibility: hidden;
|
||||
transform:translate3d(0,0,0);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#tt {
|
||||
text-align: center;
|
||||
@ -847,16 +870,26 @@ select {
|
||||
.cl {
|
||||
background-color: #000;
|
||||
}
|
||||
.sel-p {
|
||||
margin: 5px 0 10px;
|
||||
width: 5em;
|
||||
}
|
||||
.sel-pl {
|
||||
select.sel-p, select.sel-pl, select.sel-ple {
|
||||
margin: 5px 0;
|
||||
width: 100%;
|
||||
background-position: 141px 16px;
|
||||
height: 40px;
|
||||
}
|
||||
.sel-ple {
|
||||
width: 100%;
|
||||
div.sel-p {
|
||||
position: relative;
|
||||
}
|
||||
div.sel-p:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 22px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 8px solid transparent;
|
||||
border-right: 8px solid transparent;
|
||||
border-top: 8px solid var(--c-f);
|
||||
}
|
||||
select.sel-ple {
|
||||
text-align: center;
|
||||
}
|
||||
option {
|
||||
@ -1173,6 +1206,25 @@ TD .checkmark, TD .radiomark {
|
||||
left: 9px;
|
||||
}
|
||||
|
||||
.filter .fchkl {
|
||||
display: inline-block;
|
||||
min-width: 0.7em;
|
||||
padding: 4px 4px 4px 32px;
|
||||
text-align: left;
|
||||
line-height: 24px;
|
||||
vertical-align: middle;
|
||||
-webkit-filter: grayscale(100%); /* Safari 6.0 - 9.0 */
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.lbl-s {
|
||||
display: inline-block;
|
||||
/* margin: 10px 4px 0 0; */
|
||||
font-size: 13px;
|
||||
width: 48%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* list wrapper */
|
||||
.list {
|
||||
position: relative;
|
||||
@ -1226,6 +1278,7 @@ TD .checkmark, TD .radiomark {
|
||||
.lstI.sticky,
|
||||
.lstI.selected {
|
||||
z-index: 1;
|
||||
box-shadow: 0px 0px 10px 4px var(--c-1);
|
||||
}
|
||||
|
||||
#pcont .selected:not([class*="expanded"]) {
|
||||
@ -1258,6 +1311,9 @@ TD .checkmark, TD .radiomark {
|
||||
/* list item name (for sorting) */
|
||||
.lstIname {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-filter: grayscale(100%); /* Safari 6.0 - 9.0 */
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
/* list item palette preview */
|
||||
@ -1287,6 +1343,8 @@ TD .checkmark, TD .radiomark {
|
||||
border-radius: 21px;
|
||||
background: var(--c-2);
|
||||
border: 1px solid var(--c-3);
|
||||
-webkit-filter: grayscale(100%); /* Safari 6.0 - 9.0 */
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.fnd input[type="text"]:focus {
|
||||
|
@ -202,7 +202,7 @@
|
||||
<div class="staytop fnd" id="fxFind">
|
||||
<input type="text" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this,'fxlist')" />
|
||||
<i class="icons clear-icon" onclick="clean(this);"></i>
|
||||
<i class="icons search-icon"></i>
|
||||
<i class="icons search-icon" onclick="gId('filters').classList.toggle('hide');" style="cursor:pointer;"></i>
|
||||
</div>
|
||||
<div id="fxlist" class="list">
|
||||
<div class="lstI">
|
||||
@ -217,6 +217,28 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="sliders">
|
||||
<div id="filters" class="filter">
|
||||
<label id="filterPal" class="check fchkl">🎨
|
||||
<input type="checkbox" data-flt="🎨" onchange="filterFx(this)">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label id="filter1D" class="check fchkl">1D
|
||||
<input type="checkbox" data-flt="*" onchange="filterFx(this)">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label id="filter2D" class="check fchkl">2D<!-- ⊞ -->
|
||||
<input type="checkbox" data-flt="2D" onchange="filterFx(this)">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label id="filterVol" class="check fchkl">♪
|
||||
<input type="checkbox" data-flt="♪" onchange="filterFx(this)">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label id="filterFreq" class="check fchkl">♫
|
||||
<input type="checkbox" data-flt="♫" onchange="filterFx(this)">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="slider0" class="slider">
|
||||
<i class="icons slider-icon" style="cursor: pointer;" onclick="tglFreeze()"></i>
|
||||
<div class="sliderwrap il">
|
||||
|
@ -5,10 +5,10 @@ var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, sy
|
||||
var hasWhite = false, hasRGB = false, hasCCT = false;
|
||||
var nlDur = 60, nlTar = 0;
|
||||
var nlMode = false;
|
||||
var selectedFx = 0, prevFx = -1;
|
||||
var selectedFx = 0;
|
||||
var selectedPal = 0;
|
||||
var csel = 0; // selected color slot (0-2)
|
||||
var currentPreset = -1, prevPS = -1;
|
||||
var currentPreset = -1;
|
||||
var lastUpdate = 0;
|
||||
var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
||||
var pcMode = false, pcModeA = false, lastw = 0, wW;
|
||||
@ -25,7 +25,7 @@ var ws, cpick, ranges;
|
||||
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, css:true, hdays:false}
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false, css:true, hdays:false}
|
||||
};
|
||||
var hol = [
|
||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||
@ -167,12 +167,12 @@ function loadBg(iUrl)
|
||||
img.src = iUrl;
|
||||
if (iUrl == "" || iUrl==="https://picsum.photos/1920/1080") {
|
||||
var today = new Date();
|
||||
for (var i=0; i<hol.length; i++) {
|
||||
var yr = hol[i][0]==0 ? today.getFullYear() : hol[i][0];
|
||||
var hs = new Date(yr,hol[i][1],hol[i][2]);
|
||||
for (var h of (hol||[])) {
|
||||
var yr = h[0]==0 ? today.getFullYear() : h[0];
|
||||
var hs = new Date(yr,h[1],h[2]);
|
||||
var he = new Date(hs);
|
||||
he.setDate(he.getDate() + hol[i][3]);
|
||||
if (today>=hs && today<=he) img.src = hol[i][4];
|
||||
he.setDate(he.getDate() + h[3]);
|
||||
if (today>=hs && today<=he) img.src = h[4];
|
||||
}
|
||||
}
|
||||
img.addEventListener('load', (e) => {
|
||||
@ -605,7 +605,7 @@ function parseInfo(i) {
|
||||
mh = i.leds.matrix ? i.leds.matrix.h : 0;
|
||||
isM = mw>0 && mh>0;
|
||||
if (!isM) hideModes("2D ");
|
||||
if (!i.u || !i.u.AudioReactive) { /*hideModes("♪ ");*/ hideModes("♫ "); } // hide /*audio*/ frequency reactive effects
|
||||
//if (!i.u || !i.u.AudioReactive) { /*hideModes(" ♪");*/ hideModes(" ♫"); } // hide /*audio*/ frequency reactive effects
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/questions/2592092/executing-script-elements-inserted-with-innerhtml
|
||||
@ -621,6 +621,19 @@ function parseInfo(i) {
|
||||
//}
|
||||
//setInnerHTML(obj, html);
|
||||
|
||||
//https://stackoverflow.com/questions/2592092/executing-script-elements-inserted-with-innerhtml
|
||||
//var setInnerHTML = function(elm, html) {
|
||||
// elm.innerHTML = html;
|
||||
// Array.from(elm.querySelectorAll("script")).forEach( oldScript => {
|
||||
// const newScript = document.createElement("script");
|
||||
// Array.from(oldScript.attributes)
|
||||
// .forEach( attr => newScript.setAttribute(attr.name, attr.value) );
|
||||
// newScript.appendChild(document.createTextNode(oldScript.innerHTML));
|
||||
// oldScript.parentNode.replaceChild(newScript, oldScript);
|
||||
// });
|
||||
//}
|
||||
//setInnerHTML(obj, html);
|
||||
|
||||
function populateInfo(i)
|
||||
{
|
||||
var cn="";
|
||||
@ -671,17 +684,15 @@ function populateSegments(s)
|
||||
let li = lastinfo;
|
||||
segCount = 0; lowestUnused = 0; lSeg = 0;
|
||||
|
||||
for (var y = 0; y < (s.seg||[]).length; y++)
|
||||
{
|
||||
for (var inst of (s.seg||[])) {
|
||||
segCount++;
|
||||
|
||||
var inst = s.seg[y];
|
||||
let i = parseInt(inst.id);
|
||||
if (i == lowestUnused) lowestUnused = i+1;
|
||||
if (i > lSeg) lSeg = i;
|
||||
|
||||
let sg = gId(`seg${i}`);
|
||||
let exp = sg ? sg.classList.contains("expanded") : false;
|
||||
let exp = sg ? (sg.classList.contains("expanded") || (i===0 && cfg.comp.segexp)) : false;
|
||||
|
||||
let segp = `<div id="segp${i}" class="sbs">
|
||||
<i class="icons e-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})"></i>
|
||||
@ -690,17 +701,33 @@ function populateSegments(s)
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
</div>`;
|
||||
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark schk"></span></label>`;
|
||||
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark schk"></span></label>`;
|
||||
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let rvYck = "", miYck ="";
|
||||
if (isM) {
|
||||
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark schk"></span></label>`;
|
||||
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark schk"></span></label>`;
|
||||
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`;
|
||||
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`;
|
||||
}
|
||||
let map2D = `<div id="seg${i}map2D" data-map="map2D" class="lbl-s hide">Expand 1D FX<br>
|
||||
<div class="sel-p"><select class="sel-p" id="seg${i}mp12" onchange="setMp12(${i})">
|
||||
<option value="0" ${inst.mp12==0?' selected':''}>None</option>
|
||||
<option value="1" ${inst.mp12==1?' selected':''}>Bar</option>
|
||||
<option value="2" ${inst.mp12==2?' selected':''}>Arc</option>
|
||||
<option value="3" ${inst.mp12==3?' selected':''}>Corner</option>
|
||||
</select></div>
|
||||
</div>`;
|
||||
let sndSim = `<div data-snd="ssim" class="lbl-s hide">Sound sim<br>
|
||||
<div class="sel-p"><select class="sel-p" id="seg${i}ssim" onchange="setSSim(${i})">
|
||||
<option value="0" ${inst.ssim==0?' selected':''}>BeatSin</option>
|
||||
<option value="1" ${inst.ssim==1?' selected':''}>WeWillRockYou</option>
|
||||
<option value="2" ${inst.ssim==2?' selected':''}>U10_3</option>
|
||||
<option value="3" ${inst.ssim==3?' selected':''}>U14_3</option>
|
||||
</select></div>
|
||||
</div>`;
|
||||
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">
|
||||
<label class="check schkl">
|
||||
<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<i class="icons e-icon frz" id="seg${i}frz" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>
|
||||
<div class="segname" onclick="selSegEx(${i})">
|
||||
@ -741,10 +768,12 @@ function populateSegments(s)
|
||||
</table>
|
||||
<div class="h bp" id="seg${i}len"></div>
|
||||
${!isM?rvXck:''}
|
||||
${map2D}
|
||||
${s.AudioReactive && s.AudioReactive.on ? "" : sndSim}
|
||||
<label class="check revchkl">
|
||||
${isM?'Transpose':'Mirror effect'}
|
||||
<input type="checkbox" id="seg${i}${isM?'tp':'mi'}" onchange="${(isM?'setTp(':'setMi(')+i})" ${isM?(inst.tp?"checked":""):(inst.mi?"checked":"")}>
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<div class="del">
|
||||
<button class="btn btn-xs" id="segr${i}" title="Repeat until end" onclick="rptSeg(${i})"><i class="icons btn-icon"></i></button>
|
||||
@ -779,27 +808,34 @@ function populateEffects()
|
||||
var effects = eJson;
|
||||
var html = "";
|
||||
|
||||
effects.shift(); // remove solid
|
||||
for (let i = 0; i < effects.length; i++) effects[i] = {id: effects[i][0], name:effects[i][1]};
|
||||
effects.shift(); // temporary remove solid
|
||||
for (let i = 0; i < effects.length; i++) {
|
||||
effects[i] = {
|
||||
id: effects[i][0],
|
||||
name:effects[i][1]
|
||||
};
|
||||
}
|
||||
effects.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
|
||||
effects.unshift({
|
||||
"id": 0,
|
||||
"name": "Solid"
|
||||
});
|
||||
|
||||
for (let i = 0; i < effects.length; i++) {
|
||||
for (let ef of effects) {
|
||||
// WLEDSR: add slider and color control to setX (used by requestjson)
|
||||
if (effects[i].name.indexOf("Reserved") < 0) {
|
||||
let id = effects[i].id;
|
||||
html += generateListItemHtml(
|
||||
'fx',
|
||||
id,
|
||||
effects[i].name,
|
||||
'setX',
|
||||
'',
|
||||
!(Array.isArray(fxdata) && fxdata.length>id) ? '' : fxdata[id].substr(1)
|
||||
);
|
||||
let id = ef.id;
|
||||
let nm = ef.name;
|
||||
let fd = "";
|
||||
if (ef.name.indexOf("Reserved") < 0) {
|
||||
if (Array.isArray(fxdata) && fxdata.length>id) {
|
||||
fd = fxdata[id].substr(1);
|
||||
var eP = (fd == '')?[]:fd.split(";");
|
||||
var p = (eP.length<3 || eP[2]==='')?[]:eP[2].split(",");
|
||||
var m = (eP.length<4 || eP[3]==='')?[]:eP[3].split(",");
|
||||
if (isM && m.length>0) for (let r of m) { if (r.substring(0,4)=="mp12") nm += " *"; } // 1D effects with defined mapping
|
||||
if (p.length>0 && p[0].substring(0,1) === "!") nm += " 🎨";
|
||||
}
|
||||
html += generateListItemHtml('fx',id,nm,'setX','',fd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -809,7 +845,7 @@ function populateEffects()
|
||||
function populatePalettes()
|
||||
{
|
||||
var palettes = lJson;
|
||||
palettes.shift(); // remove default
|
||||
palettes.shift(); // temporary remove default
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
palettes[i] = {
|
||||
"id": palettes[i][0],
|
||||
@ -817,20 +853,19 @@ function populatePalettes()
|
||||
};
|
||||
}
|
||||
palettes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
|
||||
palettes.unshift({
|
||||
"id": 0,
|
||||
"name": "Default"
|
||||
});
|
||||
|
||||
var html = "";
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
for (let pa of palettes) {
|
||||
html += generateListItemHtml(
|
||||
'palette',
|
||||
palettes[i].id,
|
||||
palettes[i].name,
|
||||
pa.id,
|
||||
pa.name,
|
||||
'setPalette',
|
||||
`<div class="lstIprev" style="${genPalPrevCss(palettes[i].id)}"></div>`
|
||||
`<div class="lstIprev" style="${genPalPrevCss(pa.id)}"></div>`
|
||||
);
|
||||
}
|
||||
|
||||
@ -895,12 +930,12 @@ function genPalPrevCss(id)
|
||||
return `background: linear-gradient(to right,${gradient.join()});`;
|
||||
}
|
||||
|
||||
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', extraPar = '')
|
||||
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', effectPar = '')
|
||||
{
|
||||
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" data-opt="${extraPar}" onClick="${clickAction}(${id})">
|
||||
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" data-opt="${effectPar}" onClick="${clickAction}(${id})">
|
||||
<label class="radio schkl" onclick="event.preventDefault()">
|
||||
<input type="radio" value="${id}" name="${listName}">
|
||||
<span class="radiomark schk"></span>
|
||||
<span class="radiomark"></span>
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
${name}
|
||||
@ -933,8 +968,7 @@ function populateNodes(i,n)
|
||||
var nnodes = 0;
|
||||
if (n.nodes) {
|
||||
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
for (var x=0;x<n.nodes.length;x++) {
|
||||
var o = n.nodes[x];
|
||||
for (var o of n.nodes) {
|
||||
if (o.name) {
|
||||
var url = `<button class="btn" title="${o.ip}" onclick="location.assign('http://${o.ip}');">${bname(o)}</button>`;
|
||||
urows += inforow(url,`${btype(o.type)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
|
||||
@ -979,7 +1013,7 @@ function updateTrail(e)
|
||||
var max = e.hasAttribute('max') ? e.attributes.max.value : 255;
|
||||
var perc = Math.round(e.value * 100 / max);
|
||||
if (perc < 50) perc += 2;
|
||||
var val = `linear-gradient(90deg, var(--bg) ${perc}%, var(--c-4) ${perc}%)`;
|
||||
var val = `linear-gradient(90deg, var(--bg) ${perc}%, var(--c-6) ${perc}%)`;
|
||||
sd.style.backgroundImage = val;
|
||||
}
|
||||
var b = e.parentNode.parentNode.getElementsByTagName('output')[0];
|
||||
@ -1004,6 +1038,7 @@ function updateLen(s)
|
||||
start = parseInt(gId(`seg${s}sY`).value);
|
||||
stop = parseInt(gId(`seg${s}eY`).value);
|
||||
len *= (stop-(cfg.comp.seglen?0:start));
|
||||
if (stop-start>1) gId(`seg${s}map2D`).classList.remove("hide"); else gId(`seg${s}map2D`).classList.add("hide");
|
||||
}
|
||||
var out = "(delete)";
|
||||
if (len > 1) {
|
||||
@ -1109,15 +1144,21 @@ function updateSelectedFx()
|
||||
if (selEffectInput) selEffectInput.checked = true;
|
||||
|
||||
var selElement = parent.querySelector('.selected');
|
||||
if (selElement) selElement.classList.remove('selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected');
|
||||
selElement.style.bottom = null; // remove element style added in slider handling
|
||||
}
|
||||
|
||||
var selectedEffect = parent.querySelector(`.lstI[data-id="${selectedFx}"]`);
|
||||
if (selectedEffect) {
|
||||
selectedEffect.classList.add('selected');
|
||||
var fx = (selectedFx != prevFx) && currentPreset==-1; // effect changed & preset==none
|
||||
var ps = (prevPS != currentPreset) && currentPreset==-1; // preset changed & preset==none
|
||||
// WLEDSR: extract the Slider and color control string from the HTML element and set it.
|
||||
setSliderAndColorControl(selectedFx, (fx || ps));
|
||||
setEffectParameters(selectedFx);
|
||||
|
||||
var selectedName = selectedEffect.querySelector(".lstIname").innerText;
|
||||
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
||||
for (const seg of segs) if (selectedName.indexOf("2D ")<0) seg.classList.remove("hide"); else seg.classList.add("hide");
|
||||
var segs = gId("segcont").querySelectorAll(`div[data-snd="ssim"]`);
|
||||
for (const seg of segs) if (selectedName.indexOf(" ♪")<0 && selectedName.indexOf(" ♫")<0) seg.classList.add("hide"); else seg.classList.remove("hide"); // also "♫ "?
|
||||
}
|
||||
}
|
||||
|
||||
@ -1180,6 +1221,7 @@ function makeWS() {
|
||||
function readState(s,command=false)
|
||||
{
|
||||
if (!s) return false;
|
||||
if (s.success) return true; // no data to process
|
||||
|
||||
isOn = s.on;
|
||||
gId('sliderBri').value = s.bri;
|
||||
@ -1188,7 +1230,6 @@ function readState(s,command=false)
|
||||
nlTar = s.nl.tbri;
|
||||
nlFade = s.nl.fade;
|
||||
syncSend = s.udpn.send;
|
||||
prevPS = currentPreset;
|
||||
if (s.pl<0) currentPreset = s.ps;
|
||||
else currentPreset = s.pl;
|
||||
|
||||
@ -1224,7 +1265,7 @@ function readState(s,command=false)
|
||||
if (!i) {
|
||||
showToast('No Segments!', true);
|
||||
updateUI();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
var cd = gId('csl').children;
|
||||
@ -1266,11 +1307,11 @@ function readState(s,command=false)
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
|
||||
prevFx = selectedFx;
|
||||
selectedPal = i.pal;
|
||||
selectedFx = i.fx;
|
||||
redrawPalPrev(); // if any color changed (random palette did at least)
|
||||
updateUI();
|
||||
return true;
|
||||
}
|
||||
|
||||
// WLEDSR: control HTML elements for Slider and Color Control
|
||||
@ -1294,16 +1335,15 @@ function readState(s,command=false)
|
||||
// Note: Effects can override default pattern behaviour
|
||||
// - FadeToBlack can override the background setting
|
||||
// - Defining SEGCOL(<i>) can override a specific palette using these values (e.g. Color Gradient)
|
||||
function setSliderAndColorControl(idx, applyDef=false)
|
||||
function setEffectParameters(idx)
|
||||
{
|
||||
if (!(Array.isArray(fxdata) && fxdata.length>idx)) return;
|
||||
var controlDefined = (fxdata[idx].substr(0,1) == "@");
|
||||
var extra = fxdata[idx].substr(1);
|
||||
var extras = (extra == '')?[]:extra.split(";");
|
||||
var slOnOff = (extras.length==0 || extras[0]=='')?[]:extras[0].split(",");
|
||||
var coOnOff = (extras.length<2 || extras[1]=='')?[]:extras[1].split(",");
|
||||
var paOnOff = (extras.length<3 || extras[2]=='')?[]:extras[2].split(",");
|
||||
var obj = {"seg":{}};
|
||||
var effectPar = fxdata[idx].substr(1);
|
||||
var effectPars = (effectPar == '')?[]:effectPar.split(";");
|
||||
var slOnOff = (effectPars.length==0 || effectPars[0]=='')?[]:effectPars[0].split(",");
|
||||
var coOnOff = (effectPars.length<2 || effectPars[1]=='')?[]:effectPars[1].split(",");
|
||||
var paOnOff = (effectPars.length<3 || effectPars[2]=='')?[]:effectPars[2].split(",");
|
||||
|
||||
// set html slider items on/off
|
||||
var nSliders = Math.min(5,Math.floor(gId("sliders").children.length)); // div for each slider
|
||||
@ -1316,10 +1356,6 @@ function setSliderAndColorControl(idx, applyDef=false)
|
||||
if (slOnOff.length>i && slOnOff[i].indexOf("=")>0) {
|
||||
// embeded default values
|
||||
var dPos = slOnOff[i].indexOf("=");
|
||||
var v = Math.max(0,Math.min(255,parseInt(slOnOff[i].substr(dPos+1))));
|
||||
if (i==0) { if (applyDef) gId("sliderSpeed").value = v; obj.seg.sx = v; }
|
||||
else if (i==1) { if (applyDef) gId("sliderIntensity").value = v; obj.seg.ix = v; }
|
||||
else { if (applyDef) gId("sliderC"+(i-1)).value = v; obj.seg["c"+(i-1)+"x"] = v}
|
||||
slOnOff[i] = slOnOff[i].substring(0,dPos);
|
||||
}
|
||||
if (slOnOff.length>i && slOnOff[i]!="!") label.innerHTML = slOnOff[i];
|
||||
@ -1327,18 +1363,15 @@ function setSliderAndColorControl(idx, applyDef=false)
|
||||
else if (i==1) label.innerHTML = "Effect intensity";
|
||||
else label.innerHTML = "Custom" + (i-1);
|
||||
sldCnt++;
|
||||
//if (sldCnt++===0) slider.classList.add("top");
|
||||
slider.classList.remove("hide");
|
||||
//slider.setAttribute('title',label.innerHTML);
|
||||
} else {
|
||||
slider.classList.add("hide");
|
||||
//slider.classList.remove("top");
|
||||
}
|
||||
}
|
||||
|
||||
// set the bottom position of selected effect (sticky) as the top of sliders div
|
||||
let top = parseInt(getComputedStyle(gId("sliders")).height);
|
||||
/*if (sldCnt===1)*/ top += 28; // size of tooltip
|
||||
//top += 5; // size of tooltip
|
||||
let sel = d.querySelector('#fxlist .selected');
|
||||
if (sel) sel.style.bottom = top + "px"; // we will need to remove this when unselected (in setX())
|
||||
|
||||
@ -1346,7 +1379,7 @@ function setSliderAndColorControl(idx, applyDef=false)
|
||||
var cslLabel = '';
|
||||
var sep = '';
|
||||
var hide = true;
|
||||
var cslCnt = 0;
|
||||
var cslCnt = 0, oCsel = csel;
|
||||
for (let i=0; i<gId("csl").children.length; i++) {
|
||||
var btn = gId("csl" + i);
|
||||
// if no controlDefined or coOnOff has a value
|
||||
@ -1364,13 +1397,13 @@ function setSliderAndColorControl(idx, applyDef=false)
|
||||
else if (i==1) btn.innerHTML = "Bg";
|
||||
else btn.innerHTML = "Cs";
|
||||
hide = false;
|
||||
if (!cslCnt) selectSlot(i); // select 1st displayed slot
|
||||
if (!cslCnt || oCsel==i) selectSlot(i); // select 1st displayed slot or old one
|
||||
cslCnt++;
|
||||
} else if (!controlDefined /*|| paOnOff.length>0*/) { // if no controls then all buttons should be shown for color 1..3
|
||||
btn.style.display = "inline";
|
||||
btn.innerHTML = `${i+1}`;
|
||||
hide = false;
|
||||
if (!cslCnt) selectSlot(i); // select 1st displayed slot
|
||||
if (!cslCnt || oCsel==i) selectSlot(i); // select 1st displayed slot or old one
|
||||
cslCnt++;
|
||||
} else {
|
||||
btn.style.display = "none";
|
||||
@ -1388,11 +1421,6 @@ function setSliderAndColorControl(idx, applyDef=false)
|
||||
// embeded default values
|
||||
var dPos = paOnOff[0].indexOf("=");
|
||||
var v = Math.max(0,Math.min(255,parseInt(paOnOff[0].substr(dPos+1))));
|
||||
var p = d.querySelector(`#pallist input[name="palette"][value="${v}"]`);
|
||||
if (applyDef && p) {
|
||||
p.checked = true;
|
||||
obj.seg.pal = v;
|
||||
}
|
||||
paOnOff[0] = paOnOff[0].substring(0,dPos);
|
||||
}
|
||||
if (paOnOff.length>0 && paOnOff[0] != "!") pall.innerHTML = paOnOff[0];
|
||||
@ -1401,14 +1429,11 @@ function setSliderAndColorControl(idx, applyDef=false)
|
||||
// disable palett list
|
||||
pall.innerHTML = '<i class="icons sel-icon" onclick="tglHex()"></i> Color palette not used';
|
||||
palw.style.display = "none";
|
||||
// if numeric set as selected palette
|
||||
if (paOnOff.length>0 && paOnOff[0]!="" && !isNaN(paOnOff[0]) && parseInt(paOnOff[0])!=selectedPal) obj.seg.pal = parseInt(paOnOff[0]);
|
||||
}
|
||||
// not all color selectors shown, hide palettes created from color selectors
|
||||
for (let e of (gId('pallist').querySelectorAll('.lstI')||[])) {
|
||||
if (cslCnt < 3 && e.querySelector('.lstIname').innerText.indexOf("* C")>=0) e.classList.add('hide'); else e.classList.remove('hide');
|
||||
}
|
||||
if (!isEmpty(obj.seg) && applyDef) requestJson(obj); // update default values (may need throttling on ESP8266)
|
||||
}
|
||||
|
||||
var jsonTimeout;
|
||||
@ -1588,7 +1613,7 @@ function resetUtil()
|
||||
{
|
||||
// gId('segutil').innerHTML = '<button class="btn btn-s" onclick="makeSeg()"><i class="icons btn-icon"></i>segment</button>';
|
||||
gId('segutil').innerHTML = '<div class="seg btn btn-s" style="border-radius:24px;padding:0;">'
|
||||
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark schk"></span></label>'
|
||||
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark"></span></label>'
|
||||
+ '<div class="segname" onclick="makeSeg()"><i class="icons btn-icon"></i>segment</div></div>';
|
||||
}
|
||||
|
||||
@ -1601,14 +1626,14 @@ var plJson = {"0":{
|
||||
"end": 0
|
||||
}};
|
||||
|
||||
function makePlSel(incPl=false) {
|
||||
function makePlSel(el, incPl=false) {
|
||||
var plSelContent = "";
|
||||
delete pJson["0"]; // remove filler preset
|
||||
var arr = Object.entries(pJson);
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0];
|
||||
if (!incPl && arr[i][1].playlist && arr[i][1].playlist.ps) continue; // remove playlists, sub-playlists not yet supported
|
||||
plSelContent += `<option value="${arr[i][0]}">${n}</option>`
|
||||
for (var a of arr) {
|
||||
var n = a[1].n ? a[1].n : "Preset " + a[0];
|
||||
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>`
|
||||
}
|
||||
return plSelContent;
|
||||
}
|
||||
@ -1685,20 +1710,20 @@ function makeP(i,pl) {
|
||||
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 schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label class="check revchkl">Repeat indefinitely
|
||||
<input type="checkbox" id="pl${i}rptgl" onchange="plR(${i})" ${rep>0?"":"checked"}>
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<div id="pl${i}o1" style="display:${rep>0?"block":"none"}">
|
||||
<div class="c">Repeat <input class="noslide" type="number" id="pl${i}rp" oninput="plR(${i})" max=127 min=0 value=${rep>0?rep:1}> times</div>
|
||||
<div class="sel">End preset:<br>
|
||||
<select class="sel sel-ple" id="pl${i}selEnd" onchange="plR(${i})" data-val=${plJson[i].end?plJson[i].end:0}>
|
||||
<div class="sel-p"><select class="sel-ple" id="pl${i}selEnd" onchange="plR(${i})" data-val=${plJson[i].end?plJson[i].end:0}>
|
||||
<option value="0">None</option>
|
||||
<option value="255">Restore preset</option>
|
||||
${makePlSel(true)}
|
||||
</select></div>
|
||||
${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
||||
</select></div></div>
|
||||
</div>
|
||||
<div class="c"><button class="btn btn-p" onclick="testPl(${i}, this)"><i class='icons btn-icon'></i>Test</button></div>`;
|
||||
} else {
|
||||
@ -1708,24 +1733,24 @@ ${makePlSel(true)}
|
||||
Include brightness
|
||||
</span>
|
||||
<input type="checkbox" id="p${i}ibtgl" checked>
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label class="check revchkl">
|
||||
<span class="lstIname">
|
||||
Save segment bounds
|
||||
</span>
|
||||
<input type="checkbox" id="p${i}sbtgl" checked>
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label class="check revchkl">
|
||||
<span class="lstIname">
|
||||
Checked segments only
|
||||
</span>
|
||||
<input type="checkbox" id="p${i}sbchk">
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>`;
|
||||
if (Array.isArray(lastinfo.maps) && lastinfo.maps.length>0) {
|
||||
content += `<div class="sel">Ledmap: <select class="sel sel-p" id="p${i}lmp"><option value="">None</option>`;
|
||||
content += `<div class="sel">Ledmap: <select class="sel-p" id="p${i}lmp"><option value="">None</option>`;
|
||||
for (const k of (lastinfo.maps||[])) content += `<option value="${k}"${(i>0 && pJson[i].ledmap==k)?" selected":""}>${k}</option>`;
|
||||
content += "</select></div>";
|
||||
}
|
||||
@ -1740,7 +1765,7 @@ ${makePlSel(true)}
|
||||
${pl?"Show playlist editor":(i>0)?"Overwrite with state":"Use current state"}
|
||||
</span>
|
||||
<input type="checkbox" id="p${i}cstgl" onchange="tglCs(${i})" ${(i==0||pl)?"checked":""}>
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="po2" id="p${i}o2">
|
||||
@ -1778,9 +1803,9 @@ function makePlEntry(p,i) {
|
||||
<table>
|
||||
<tr>
|
||||
<td width="80%" colspan=2>
|
||||
<select class="sel sel-pl" onchange="plePs(${p},${i},this)" data-val="${plJson[p].ps[i]}" data-index="${i}">
|
||||
${makePlSel()}
|
||||
</select>
|
||||
<div class="sel-p"><select class="sel-pl" onchange="plePs(${p},${i},this)" data-val="${plJson[p].ps[i]}" data-index="${i}">
|
||||
${makePlSel(plJson[p].ps[i])}
|
||||
</select></div>
|
||||
</td>
|
||||
<td class="c"><button class="btn btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon"></i></button></td>
|
||||
</tr>
|
||||
@ -1952,6 +1977,20 @@ function setMiY(s)
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setMp12(s)
|
||||
{
|
||||
var value = gId(`seg${s}mp12`).selectedIndex;
|
||||
var obj = {"seg": {"id": s, "mp12": value}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setSSim(s)
|
||||
{
|
||||
var value = gId(`seg${s}ssim`).selectedIndex;
|
||||
var obj = {"seg": {"id": s, "ssim": value}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setTp(s)
|
||||
{
|
||||
var tp = gId(`seg${s}tp`).checked;
|
||||
@ -1990,6 +2029,8 @@ function setX(ind = null)
|
||||
} else {
|
||||
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
||||
}
|
||||
/*
|
||||
// this code also in updateSelectedFx
|
||||
var selElement = d.querySelector('#fxlist .selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected');
|
||||
@ -1997,7 +2038,7 @@ function setX(ind = null)
|
||||
}
|
||||
|
||||
d.querySelector(`#fxlist .lstI[data-id="${ind}"]`).classList.add('selected');
|
||||
|
||||
*/
|
||||
var obj = {"seg": {"fx": parseInt(ind)}};
|
||||
requestJson(obj);
|
||||
}
|
||||
@ -2009,11 +2050,13 @@ function setPalette(paletteId = null)
|
||||
} else {
|
||||
d.querySelector(`#pallist input[name="palette"][value="${paletteId}"]`).checked = true;
|
||||
}
|
||||
/*
|
||||
var selElement = d.querySelector('#pallist .selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
d.querySelector(`#pallist .lstI[data-id="${paletteId}"]`).classList.add('selected');
|
||||
*/
|
||||
var obj = {"seg": {"pal": paletteId}};
|
||||
requestJson(obj);
|
||||
}
|
||||
@ -2127,6 +2170,7 @@ function saveP(i,pl)
|
||||
}
|
||||
populatePresets();
|
||||
resetPUtil();
|
||||
setTimeout(()=>{pmtLast=0; loadPresets();}, 500); // force reloading of presets
|
||||
}
|
||||
|
||||
function testPl(i,bt) {
|
||||
@ -2362,6 +2406,11 @@ function rSegs()
|
||||
bt.style.color = "var(--c-f)";
|
||||
bt.innerHTML = "Reset segments";
|
||||
var obj = {"seg":[{"start":0,"stop":ledCount,"sel":true}]};
|
||||
if (isM) {
|
||||
obj.seg[0].stop = mw;
|
||||
obj.seg[0].startX = 0;
|
||||
obj.seg[0].stopY = mh;
|
||||
}
|
||||
for (let i=1; i<=lSeg; i++) obj.seg.push({"stop":0});
|
||||
requestJson(obj);
|
||||
}
|
||||
@ -2422,6 +2471,10 @@ function hideModes(txt)
|
||||
for (let e of (gId('fxlist').querySelectorAll('.lstI')||[])) {
|
||||
if (e.querySelector('.lstIname').innerText.indexOf(txt) >= 0) e.classList.add("hide"); //else e.classList.remove("hide");
|
||||
}
|
||||
if (txt==="2D ") {
|
||||
gId("filter1D").classList.add("hide");
|
||||
gId("filter2D").classList.add("hide");
|
||||
}
|
||||
}
|
||||
|
||||
function search(f,l=null)
|
||||
@ -2444,6 +2497,19 @@ function clean(c)
|
||||
i.value='';
|
||||
i.focus();
|
||||
i.dispatchEvent(new Event('input'));
|
||||
if (i.parentElement.id=='fxFind') {
|
||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e)=>{e.checked=false;});
|
||||
}
|
||||
}
|
||||
|
||||
function filterFx(o)
|
||||
{
|
||||
if (!o) return;
|
||||
let i = gId('fxFind').children[0];
|
||||
i.value=!o.checked?'':o.dataset.flt;
|
||||
i.focus();
|
||||
i.dispatchEvent(new Event('input'));
|
||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e)=>{if(e!==o)e.checked=false;});
|
||||
}
|
||||
|
||||
// make sure "dur" and "transition" are arrays with at least the length of "ps"
|
||||
|
@ -6,9 +6,38 @@
|
||||
<title>WLED Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
function gId(n){return d.getElementById(n);}
|
||||
function S(){GetV();}
|
||||
function GetV(){}
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
GetV();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=0';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
|
@ -41,8 +41,6 @@
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
//if (loc) loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
//else { GetV(); UI(); }
|
||||
}
|
||||
|
||||
var maxPanels=64;
|
||||
@ -104,9 +102,6 @@ Serpentine: <input type="checkbox" name="P${i}S"></div>`;
|
||||
gId("pnl_add").style.display = (i<maxPanels) ? "inline":"none";
|
||||
gId("pnl_rem").style.display = (i>1) ? "inline":"none";
|
||||
}
|
||||
|
||||
//values injected by server while sending HTML
|
||||
//fun-ction GetV() {}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
|
@ -6,35 +6,65 @@
|
||||
<meta charset="utf-8">
|
||||
<title>DMX Settings</title>
|
||||
<script>
|
||||
function GCH(num) {
|
||||
d=document;
|
||||
d.getElementById('dmxchannels').innerHTML += "";
|
||||
for (i=0;i<num;i++) {
|
||||
d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n";
|
||||
}
|
||||
}
|
||||
function mMap(){
|
||||
d=document;
|
||||
numCh=document.Sf.CN.value;
|
||||
numGap=document.Sf.CG.value;
|
||||
if (parseInt(numCh)>parseInt(numGap)) {
|
||||
d.getElementById("gapwarning").style.display="block";
|
||||
} else {
|
||||
d.getElementById("gapwarning").style.display="none";
|
||||
}
|
||||
for (i=0;i<15;i++) {
|
||||
if (i>=numCh) {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5";
|
||||
d.getElementById("CH"+(i+1)).disabled = true;
|
||||
|
||||
} else {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "1";
|
||||
d.getElementById("CH"+(i+1)).disabled = false;
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
|
||||
function B(){window.history.back();}
|
||||
function GCH(num) {
|
||||
d.getElementById('dmxchannels').innerHTML += "";
|
||||
for (i=0;i<num;i++) {
|
||||
d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}
|
||||
function GetV(){}
|
||||
function mMap(){
|
||||
numCh=document.Sf.CN.value;
|
||||
numGap=document.Sf.CG.value;
|
||||
if (parseInt(numCh)>parseInt(numGap)) {
|
||||
d.getElementById("gapwarning").style.display="block";
|
||||
} else {
|
||||
d.getElementById("gapwarning").style.display="none";
|
||||
}
|
||||
for (i=0;i<15;i++) {
|
||||
if (i>=numCh) {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5";
|
||||
d.getElementById("CH"+(i+1)).disabled = true;
|
||||
|
||||
} else {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "1";
|
||||
d.getElementById("CH"+(i+1)).disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
GCH(15);GetV();mMap();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=7';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
|
@ -8,10 +8,29 @@
|
||||
<script>
|
||||
var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
|
||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||
var loc = false, locip;
|
||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function gId(n){return d.getElementById(n);}
|
||||
function off(n){d.getElementsByName(n)[0].value = -1;}
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
GetV();checkSi();setABL();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
var timeout;
|
||||
function showToast(text, error = false)
|
||||
{
|
||||
@ -506,12 +525,17 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
}
|
||||
}
|
||||
}
|
||||
function S(){GetV();checkSi();setABL();}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
//d.um_p=[6,7,8,9,10,11,1];bLimits(3,4096,4000,1664);d.Sf.MS.checked=1;addLEDs(1);d.Sf.L00.value=2;d.Sf.LC0.value=30;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=15;d.Sf.CV0.checked=1;d.Sf.SL0.checked=0;addLEDs(1);d.Sf.L01.value=10;d.Sf.L11.value=10;d.Sf.L21.value=1;d.Sf.L31.value=10;d.Sf.LC1.value=60;d.Sf.LT1.value=80;d.Sf.CO1.value=1;d.Sf.LS1.value=0;d.Sf.CV1.checked=0;d.Sf.SL1.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=56;d.Sf.AW.value=3;d.Sf.BO.checked=1;d.Sf.BP.value=80;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=0;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=1;addBtn(0,0,0);addBtn(1,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=0;
|
||||
//d.um_p=[6,7,8,9,10,11,14,15,13,1,21,19,22,25,26,27,5,23,18,17];bLimits(10,2048,64000,8192);d.Sf.MS.checked=1;d.Sf.CCT.checked=0;addLEDs(1);d.Sf.L00.value=192;d.Sf.L10.value=168;d.Sf.L20.value=0;d.Sf.L30.value=61;d.Sf.LC0.value=421;d.Sf.LT0.value=80;d.Sf.CO0.value=1;d.Sf.LS0.value=0;d.Sf.CV0.checked=0;d.Sf.SL0.checked=0;d.Sf.RF0.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=127;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=0;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=1;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=-1;d.Sf.RM.checked=1;addBtn(0,-1,0);addBtn(1,-1,0);addBtn(2,-1,0);addBtn(3,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=8;
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=2';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
|
@ -7,11 +7,30 @@
|
||||
<title>Misc Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var loc = false, locip;
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function U() { window.open("/update","_self"); }
|
||||
function gId(s) { return d.getElementById(s); }
|
||||
function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
GetV();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
var timeout;
|
||||
function showToast(text, error = false)
|
||||
{
|
||||
@ -40,16 +59,24 @@
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=6';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
</head>
|
||||
<body onload="GetV()">
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
|
@ -5,42 +5,71 @@
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||
<meta charset="utf-8">
|
||||
<title>Sync Settings</title>
|
||||
<script>var d=document;
|
||||
function gId(s)
|
||||
{
|
||||
return d.getElementById(s);
|
||||
}
|
||||
function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
|
||||
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
|
||||
function FC()
|
||||
{
|
||||
for(j=0;j<8;j++)
|
||||
<script>var d=document;
|
||||
var loc = false, locip;
|
||||
function gId(s)
|
||||
{
|
||||
gId("G"+(j+1)).checked=gId("GS").value>>j&1;
|
||||
gId("R"+(j+1)).checked=gId("GR").value>>j&1;
|
||||
return d.getElementById(s);
|
||||
}
|
||||
}
|
||||
function GC()
|
||||
{
|
||||
var a=0, b=0;
|
||||
function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
|
||||
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
GetV();SetVal();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function FC()
|
||||
{
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
gId("G"+(j+1)).checked=gId("GS").value>>j&1;
|
||||
gId("R"+(j+1)).checked=gId("GR").value>>j&1;
|
||||
}
|
||||
}
|
||||
function GC()
|
||||
{
|
||||
var a=0, b=0;
|
||||
|
||||
var m=1;
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a+=gId("G"+(j+1)).checked*m;
|
||||
b+=gId("R"+(j+1)).checked*m;
|
||||
m*=2;
|
||||
var m=1;
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a+=gId("G"+(j+1)).checked*m;
|
||||
b+=gId("R"+(j+1)).checked*m;
|
||||
m*=2;
|
||||
}
|
||||
gId("GS").value=a;
|
||||
gId("GR").value=b;
|
||||
}
|
||||
gId("GS").value=a;
|
||||
gId("GR").value=b;
|
||||
}
|
||||
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
||||
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();}
|
||||
function S(){GetV();SetVal();}
|
||||
function GetV(){var d=document;}
|
||||
</script>
|
||||
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
||||
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();}
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=4';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
|
@ -7,26 +7,42 @@
|
||||
<title>Time Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
var el=false;
|
||||
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
function H()
|
||||
{
|
||||
window.open("https://kno.wled.ge/features/settings/#time-settings");
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#time-settings"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function gId(s) { return d.getElementById(s); }
|
||||
function gN(s) { return d.getElementsByName(s)[0]; }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
BTa();GetV();updLoc();Cs();FC();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function B()
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
}
|
||||
function S()
|
||||
{
|
||||
BTa();GetV();updLoc();Cs();FC();
|
||||
}
|
||||
function gId(s)
|
||||
{
|
||||
return d.getElementById(s);
|
||||
}
|
||||
function gN(s) {
|
||||
return d.getElementsByName(s)[0];
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=5';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
function expand(o,i)
|
||||
{
|
||||
@ -34,10 +50,7 @@
|
||||
t.style.display = t.style.display!=="none" ? "none" : "";
|
||||
o.innerHTML = t.style.display==="none" ? "📅" : "✕";
|
||||
}
|
||||
function Cs()
|
||||
{
|
||||
gId("cac").style.display=(gN("OL").checked)?"block":"none";
|
||||
}
|
||||
function Cs() { gId("cac").style.display=(gN("OL").checked)?"block":"none"; }
|
||||
function BTa()
|
||||
{
|
||||
var ih="<thead><tr><th>En.</th><th>Hour</th><th>Minute</th><th>Preset</th><th></th></tr></thead>";
|
||||
@ -132,10 +145,6 @@
|
||||
if (parseFloat(d.Sf.LT.value)<0) { d.Sf.LTR.value = "S"; d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); } else d.Sf.LTR.value = "N";
|
||||
if (parseFloat(d.Sf.LN.value)<0) { d.Sf.LNR.value = "W"; d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); } else d.Sf.LNR.value = "E";
|
||||
}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<title>UI Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var loc = false, locip;
|
||||
var initial_ds, initial_st, initial_su;
|
||||
var sett = null;
|
||||
var l = {
|
||||
@ -23,6 +24,7 @@
|
||||
"pid": "Show preset IDs",
|
||||
"seglen": "Set segment length instead of stop LED",
|
||||
"segpwr": "Hide segment power & brightness",
|
||||
"segexp" : "Always expand first segment",
|
||||
"css": "Enable custom CSS",
|
||||
"hdays": "Enable custom Holidays list"
|
||||
},
|
||||
@ -40,10 +42,7 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
function gId(s)
|
||||
{
|
||||
return d.getElementById(s);
|
||||
}
|
||||
function gId(s) { return d.getElementById(s); }
|
||||
function isObject(item) {
|
||||
return (item && typeof item === 'object' && !Array.isArray(item));
|
||||
}
|
||||
@ -163,22 +162,43 @@
|
||||
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st || d.Sf.SU.checked != initial_su) d.Sf.submit();
|
||||
}
|
||||
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
GetV();
|
||||
initial_ds = d.Sf.DS.value;
|
||||
initial_st = d.Sf.ST.checked;
|
||||
initial_su = d.Sf.SU.checked;
|
||||
GetLS();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S()
|
||||
{
|
||||
GetV();
|
||||
initial_ds = d.Sf.DS.value;
|
||||
initial_st = d.Sf.ST.checked;
|
||||
initial_su = d.Sf.SU.checked;
|
||||
GetLS();
|
||||
}
|
||||
function H()
|
||||
{
|
||||
window.open("https://kno.wled.ge/features/settings/#user-interface-settings");
|
||||
}
|
||||
function B()
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=3';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function UI()
|
||||
{
|
||||
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
|
||||
@ -213,7 +233,6 @@
|
||||
fO.value = '';
|
||||
return false;
|
||||
}
|
||||
function GetV(){var d=document;}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
@ -241,6 +260,7 @@
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_pid" class="agi cb"><br>
|
||||
<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>
|
||||
I hate dark mode: <input type="checkbox" id="dm" onchange="UI()"><br>
|
||||
<span id="idonthateyou" style="display:none"><i>Why would you? </i>🥺<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>
|
||||
|
@ -81,6 +81,7 @@
|
||||
}
|
||||
function addField(k,f,o,a=false) { //key, field, (sub)object, isArray
|
||||
if (isO(o)) {
|
||||
urows += '<hr style="width:260px">';
|
||||
for (const [s,v] of Object.entries(o)) {
|
||||
// possibility to nest objects (only 1 level)
|
||||
if (f!=='unknown' && !k.includes(":")) addField(k+":"+f,s,v);
|
||||
@ -191,7 +192,6 @@
|
||||
e.preventDefault();
|
||||
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
|
||||
}
|
||||
//fun-ction GetV() {} // replaced during 'npm run build'
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
|
@ -6,16 +6,44 @@
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||
<title>WiFi Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
scE.setAttribute("src", FILE_URL);
|
||||
scE.setAttribute("type", "text/javascript");
|
||||
scE.setAttribute("async", async);
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
//console.log("File loaded");
|
||||
GetV();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
console.log("Error on loading file", ev);
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=1';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
<body onload="GetV()">
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
|
@ -58,6 +58,9 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
|
||||
|
||||
//colors.cpp
|
||||
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||
uint32_t color_add(uint32_t,uint32_t);
|
||||
|
||||
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);
|
||||
@ -129,7 +132,7 @@ void handleIR();
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
|
||||
bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true);
|
||||
void serializeInfo(JsonObject root);
|
||||
void serializeModeNames(JsonArray arr, const char *qstring);
|
||||
@ -296,7 +299,7 @@ class UsermodManager {
|
||||
void onUpdateBegin(bool);
|
||||
bool add(Usermod* um);
|
||||
Usermod* lookup(uint16_t mod_id);
|
||||
byte getModCount();
|
||||
byte getModCount() {return numMods;};
|
||||
};
|
||||
|
||||
//usermods_list.cpp
|
||||
@ -321,8 +324,10 @@ bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
bool requestJSONBufferLock(uint8_t module=255);
|
||||
void releaseJSONBufferLock();
|
||||
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen);
|
||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr);
|
||||
int16_t extractModeDefaults(uint8_t mode, const char *segVar);
|
||||
uint16_t crc16(const unsigned char* data_p, size_t length);
|
||||
um_data_t* simulateSound(uint8_t simulationId);
|
||||
|
||||
//wled_eeprom.cpp
|
||||
void applyMacro(byte index);
|
||||
|
File diff suppressed because it is too large
Load Diff
3597
wled00/html_ui.h
3597
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -89,8 +89,8 @@ byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte highe
|
||||
void changeEffect(uint8_t fx)
|
||||
{
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
strip.setMode(i, fx);
|
||||
}
|
||||
@ -105,8 +105,8 @@ void changeEffect(uint8_t fx)
|
||||
void changePalette(uint8_t pal)
|
||||
{
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.palette = pal;
|
||||
}
|
||||
@ -124,8 +124,8 @@ void changeEffectSpeed(int8_t amount)
|
||||
int16_t new_val = (int16_t) effectSpeed + amount;
|
||||
effectSpeed = (byte)constrain(new_val,0,255);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
@ -135,7 +135,7 @@ void changeEffectSpeed(int8_t amount)
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
} else { // if Effect == "solid Color", change the hue of the primary color
|
||||
WS2812FX::Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = R(sseg.colors[0]);
|
||||
fastled_col.green = G(sseg.colors[0]);
|
||||
@ -147,8 +147,8 @@ void changeEffectSpeed(int8_t amount)
|
||||
prim_hsv.h = (byte)new_val;
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
}
|
||||
@ -171,8 +171,8 @@ void changeEffectIntensity(int8_t amount)
|
||||
int16_t new_val = (int16_t) effectIntensity + amount;
|
||||
effectIntensity = (byte)constrain(new_val,0,255);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
@ -182,7 +182,7 @@ void changeEffectIntensity(int8_t amount)
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
} else { // if Effect == "solid Color", change the saturation of the primary color
|
||||
WS2812FX::Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = R(sseg.colors[0]);
|
||||
fastled_col.green = G(sseg.colors[0]);
|
||||
@ -192,8 +192,8 @@ void changeEffectIntensity(int8_t amount)
|
||||
prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
}
|
||||
@ -214,8 +214,8 @@ void changeColor(uint32_t c, int16_t cct=-1)
|
||||
{
|
||||
if (irApplyToAllSelected) {
|
||||
// main segment may not be selected!
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
byte capabilities = seg.getLightCapabilities();
|
||||
uint32_t mask = 0;
|
||||
@ -226,14 +226,14 @@ void changeColor(uint32_t c, int16_t cct=-1)
|
||||
if (isRGB) mask |= 0x00FFFFFF; // RGB
|
||||
if (hasW) mask |= 0xFF000000; // white
|
||||
if (hasW && !wSlider && (c & 0xFF000000)) { // segment has white channel & white channel is auto calculated & white specified
|
||||
seg.setColor(0, c | 0xFFFFFF, i); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
|
||||
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
|
||||
if (isCCT && cct >= 0) seg.setCCT(cct, i);
|
||||
seg.setColor(0, c | 0xFFFFFF); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
|
||||
} else if (c & mask) seg.setColor(0, c & mask); // only apply if not black
|
||||
if (isCCT && cct >= 0) seg.setCCT(cct);
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
byte i = strip.getMainSegmentId();
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
byte capabilities = seg.getLightCapabilities();
|
||||
uint32_t mask = 0;
|
||||
bool isRGB = GET_BIT(capabilities, 0); // is segment RGB capable
|
||||
@ -243,9 +243,9 @@ void changeColor(uint32_t c, int16_t cct=-1)
|
||||
if (isRGB) mask |= 0x00FFFFFF; // RGB
|
||||
if (hasW) mask |= 0xFF000000; // white
|
||||
if (hasW && !wSlider && (c & 0xFF000000)) { // segment has white channel & white channel is auto calculated & white specified
|
||||
seg.setColor(0, c | 0xFFFFFF, i); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
|
||||
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
|
||||
if (isCCT && cct >= 0) seg.setCCT(cct, i);
|
||||
seg.setColor(0, c | 0xFFFFFF); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
|
||||
} else if (c & mask) seg.setColor(0, c & mask); // only apply if not black
|
||||
if (isCCT && cct >= 0) seg.setCCT(cct);
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
stateChanged = true;
|
||||
@ -253,7 +253,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
|
||||
|
||||
void changeWhite(int8_t amount, int16_t cct=-1)
|
||||
{
|
||||
WS2812FX::Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
byte r = R(seg.colors[0]);
|
||||
byte g = G(seg.colors[0]);
|
||||
byte b = B(seg.colors[0]);
|
||||
@ -424,7 +424,7 @@ void decodeIR24CT(uint32_t code)
|
||||
|
||||
void decodeIR40(uint32_t code)
|
||||
{
|
||||
WS2812FX::Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
byte r = R(seg.colors[0]);
|
||||
byte g = G(seg.colors[0]);
|
||||
byte b = B(seg.colors[0]);
|
||||
@ -712,7 +712,7 @@ void initIR()
|
||||
|
||||
void handleIR()
|
||||
{
|
||||
if (irEnabled > 0 && millis() - irCheckedTime > 120)
|
||||
if (irEnabled > 0 && millis() - irCheckedTime > 120 && !strip.isUpdating())
|
||||
{
|
||||
irCheckedTime = millis();
|
||||
if (irEnabled > 0)
|
||||
|
172
wled00/json.cpp
172
wled00/json.cpp
@ -11,11 +11,19 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
byte id = elem["id"] | it;
|
||||
if (id >= strip.getMaxSegments()) return;
|
||||
|
||||
WS2812FX::Segment& seg = strip.getSegment(id);
|
||||
WS2812FX::Segment prev = seg; //make a backup so we can tell if something changed
|
||||
int stop = elem["stop"] | -1;
|
||||
|
||||
// if using vectors use this code to append segment
|
||||
if (id >= strip.getSegmentsNum()) {
|
||||
if (stop <= 0) return; // ignore empty/inactive segments
|
||||
strip.appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
id = strip.getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
|
||||
Segment& seg = strip.getSegment(id);
|
||||
Segment prev = seg; //make a backup so we can tell if something changed
|
||||
|
||||
uint16_t start = elem["start"] | seg.start;
|
||||
int stop = elem["stop"] | -1;
|
||||
if (stop < 0) {
|
||||
uint16_t len = elem["len"];
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
@ -31,7 +39,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
elem.remove("rpt"); // remove for recursive call
|
||||
elem.remove("n"); // remove for recursive call
|
||||
uint16_t len = stop - start;
|
||||
for (byte i=id+1; i<strip.getMaxSegments(); i++) {
|
||||
for (size_t i=id+1; i<strip.getMaxSegments(); i++) {
|
||||
start = start + len;
|
||||
if (start >= strip.getLengthTotal()) break;
|
||||
//TODO: add support for 2D
|
||||
@ -70,9 +78,14 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
uint16_t grp = elem["grp"] | seg.grouping;
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
uint16_t of = seg.offset;
|
||||
uint16_t of = seg.offset;
|
||||
uint8_t soundSim = elem[F("ssim")] | seg.soundSim;
|
||||
uint8_t map1D2D = elem[F("mp12")] | seg.map1D2D;
|
||||
|
||||
if (spc>0 && spc!=seg.spacing) strip.fill(BLACK, id); // clear spacing gaps
|
||||
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
|
||||
|
||||
seg.map1D2D = map1D2D & 0x03;
|
||||
seg.soundSim = soundSim & 0x07;
|
||||
|
||||
uint16_t len = 1;
|
||||
if (stop > start) len = stop - start;
|
||||
@ -88,23 +101,23 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
byte segbri = seg.opacity;
|
||||
if (getVal(elem["bri"], &segbri)) {
|
||||
if (segbri > 0) seg.setOpacity(segbri, id);
|
||||
seg.setOption(SEG_OPTION_ON, segbri, id);
|
||||
if (segbri > 0) seg.setOpacity(segbri);
|
||||
seg.setOption(SEG_OPTION_ON, segbri);
|
||||
}
|
||||
|
||||
bool on = elem["on"] | seg.getOption(SEG_OPTION_ON);
|
||||
if (elem["on"].is<const char*>() && elem["on"].as<const char*>()[0] == 't') on = !on;
|
||||
seg.setOption(SEG_OPTION_ON, on, id);
|
||||
seg.setOption(SEG_OPTION_ON, on);
|
||||
bool frz = elem["frz"] | seg.getOption(SEG_OPTION_FREEZE);
|
||||
if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.getOption(SEG_OPTION_FREEZE);
|
||||
seg.setOption(SEG_OPTION_FREEZE, frz, id);
|
||||
seg.setOption(SEG_OPTION_FREEZE, frz);
|
||||
|
||||
seg.setCCT(elem["cct"] | seg.cct, id);
|
||||
seg.setCCT(elem["cct"] | seg.cct);
|
||||
|
||||
JsonArray colarr = elem["col"];
|
||||
if (!colarr.isNull())
|
||||
{
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
{
|
||||
int rgbw[] = {0,0,0,0};
|
||||
bool colValid = false;
|
||||
@ -115,13 +128,13 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
|
||||
int kelvin = colarr[i] | -1;
|
||||
if (kelvin < 0) continue;
|
||||
if (kelvin == 0) seg.setColor(i, 0, id);
|
||||
if (kelvin == 0) seg.setColor(i, 0);
|
||||
if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
|
||||
colValid = true;
|
||||
} else { //HEX string, e.g. "FFAA00"
|
||||
colValid = colorFromHexString(brgbw, hexCol);
|
||||
}
|
||||
for (uint8_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
for (size_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
} else { //Array of ints (RGB or RGBW color), e.g. [255,160,0]
|
||||
byte sz = colX.size();
|
||||
if (sz == 0) continue; //do nothing on empty array
|
||||
@ -132,7 +145,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
if (!colValid) continue;
|
||||
|
||||
seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]), id);
|
||||
seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]));
|
||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||
}
|
||||
}
|
||||
@ -149,31 +162,74 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
#endif
|
||||
|
||||
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
|
||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
||||
// 2D options
|
||||
seg.setOption(SEG_OPTION_SELECTED, elem["sel"] | seg.getOption(SEG_OPTION_SELECTED));
|
||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
||||
#ifndef WLED_DISABLE_2D
|
||||
seg.setOption(SEG_OPTION_REVERSED_Y, elem[F("rY")] | seg.getOption(SEG_OPTION_REVERSED_Y));
|
||||
seg.setOption(SEG_OPTION_MIRROR_Y , elem[F("mY")] | seg.getOption(SEG_OPTION_MIRROR_Y ));
|
||||
seg.setOption(SEG_OPTION_TRANSPOSED, elem[F("tp")] | seg.getOption(SEG_OPTION_TRANSPOSED));
|
||||
#endif
|
||||
|
||||
byte fx = seg.mode;
|
||||
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
|
||||
if (getVal(elem["fx"], &fx, 0, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value)
|
||||
if (!presetId && currentPlaylist>=0) unloadPlaylist();
|
||||
strip.setMode(id, fx);
|
||||
if (fx != seg.mode) {
|
||||
//seg.startTransition(strip.getTransition()); // set effect transitions
|
||||
seg.markForReset();
|
||||
seg.mode = fx;
|
||||
// load default values from effect string if effect is selected without
|
||||
// any other effect parameter (i.e. effect clicked in UI)
|
||||
if ( elem[F("sx")].isNull()
|
||||
&& elem[F("ix")].isNull()
|
||||
&& elem["pal"].isNull()
|
||||
&& elem[F("c1")].isNull()
|
||||
&& elem[F("c2")].isNull()
|
||||
&& elem[F("c3")].isNull() )
|
||||
{
|
||||
// compatibility mode begin
|
||||
char buf[5]; // dummy buffer
|
||||
for (int i=0; i<5; i++) {
|
||||
uint8_t *var;
|
||||
switch (i) {
|
||||
case 0: var = &seg.speed; break;
|
||||
case 1: var = &seg.intensity; break;
|
||||
case 2: var = &seg.custom1; break;
|
||||
case 3: var = &seg.custom2; break;
|
||||
case 4: var = &seg.custom3; break;
|
||||
}
|
||||
extractModeSlider(fx, i, buf, 4, var);
|
||||
}
|
||||
extractModeSlider(fx, 255, buf, 4, &seg.palette);
|
||||
//end compatibility mode
|
||||
int16_t sOpt;
|
||||
sOpt = extractModeDefaults(fx, SET_F("sx")); if (sOpt >= 0) seg.speed = sOpt;
|
||||
sOpt = extractModeDefaults(fx, SET_F("ix")); if (sOpt >= 0) seg.intensity = sOpt;
|
||||
sOpt = extractModeDefaults(fx, SET_F("c1")); if (sOpt >= 0) seg.custom1 = sOpt;
|
||||
sOpt = extractModeDefaults(fx, SET_F("c2")); if (sOpt >= 0) seg.custom2 = sOpt;
|
||||
sOpt = extractModeDefaults(fx, SET_F("c3")); if (sOpt >= 0) seg.custom3 = sOpt;
|
||||
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0 && sOpt < strip.getPaletteCount()) seg.palette = sOpt;
|
||||
sOpt = extractModeDefaults(fx, SET_F("mp12")); if (sOpt >= 0) seg.map1D2D = sOpt & 0x03;
|
||||
sOpt = extractModeDefaults(fx, SET_F("ssim")); if (sOpt >= 0) seg.soundSim = sOpt & 0x07;
|
||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) seg.reverse = (bool)sOpt; // setOption(SEG_OPTION_REVERSED, (bool)sOpt); // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, SET_F("mi")); if (sOpt >= 0) seg.mirror = (bool)sOpt; // setOption(SEG_OPTION_MIRROR, (bool)sOpt); // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, SET_F("rY")); if (sOpt >= 0) seg.reverse_y = (bool)sOpt; // setOption(SEG_OPTION_REVERSED_Y, (bool)sOpt); // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, SET_F("mY")); if (sOpt >= 0) seg.mirror_y = (bool)sOpt; // setOption(SEG_OPTION_MIRROR_Y, (bool)sOpt); // NOTE: setting this option is a risky business
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//getVal also supports inc/decrementing and random
|
||||
getVal(elem[F("sx")], &seg.speed);
|
||||
getVal(elem[F("ix")], &seg.intensity);
|
||||
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
||||
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
||||
getVal(elem[F("c1")], &seg.custom1);
|
||||
getVal(elem[F("c2")], &seg.custom2);
|
||||
getVal(elem[F("c3")], &seg.custom3);
|
||||
|
||||
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
||||
if (!iarr.isNull()) {
|
||||
uint8_t oldSegId = strip.setPixelSegment(id);
|
||||
//uint8_t oldSegId = strip.setPixelSegment(id);
|
||||
|
||||
// set brightness immediately and disable transition
|
||||
transitionDelayTemp = 0;
|
||||
@ -183,13 +239,13 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
// freeze and init to black
|
||||
if (!seg.getOption(SEG_OPTION_FREEZE)) {
|
||||
seg.setOption(SEG_OPTION_FREEZE, true);
|
||||
strip.fill(0);
|
||||
seg.fill(BLACK);
|
||||
}
|
||||
|
||||
uint16_t start = 0, stop = 0;
|
||||
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
||||
|
||||
for (uint16_t i = 0; i < iarr.size(); i++) {
|
||||
for (size_t i = 0; i < iarr.size(); i++) {
|
||||
if(iarr[i].is<JsonInteger>()) {
|
||||
if (!set) {
|
||||
start = iarr[i];
|
||||
@ -208,29 +264,28 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = iarr[i];
|
||||
if (colorFromHexString(brgbw, hexCol)) {
|
||||
for (uint8_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
for (size_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
}
|
||||
}
|
||||
|
||||
if (set < 2) stop = start + 1;
|
||||
for (uint16_t i = start; i < stop; i++) {
|
||||
for (int i = start; i < stop; i++) {
|
||||
if (strip.gammaCorrectCol) {
|
||||
strip.setPixelColor(i, strip.gamma8(rgbw[0]), strip.gamma8(rgbw[1]), strip.gamma8(rgbw[2]), strip.gamma8(rgbw[3]));
|
||||
seg.setPixelColor(i, strip.gamma8(rgbw[0]), strip.gamma8(rgbw[1]), strip.gamma8(rgbw[2]), strip.gamma8(rgbw[3]));
|
||||
} else {
|
||||
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
seg.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
}
|
||||
if (!set) start++;
|
||||
set = 0;
|
||||
}
|
||||
}
|
||||
strip.setPixelSegment(oldSegId);
|
||||
//strip.setPixelSegment(oldSegId);
|
||||
strip.trigger();
|
||||
}
|
||||
// send UDP if not in preset and something changed that is not just selection
|
||||
// send UDP if something changed that is not just selection or segment power/opacity
|
||||
if ((seg.differs(prev) & 0x7E) && seg.getOption(SEG_OPTION_ON)==prev.getOption(SEG_OPTION_ON)) stateChanged = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// deserializes WLED state (fileDoc points to doc object if called from web server)
|
||||
@ -248,11 +303,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
if (root["on"].is<const char*>() && root["on"].as<const char*>()[0] == 't') toggleOnOff();
|
||||
|
||||
if (bri && !onBefore) { // unfreeze all segments when turning on
|
||||
for (uint8_t s=0; s < strip.getMaxSegments(); s++) {
|
||||
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, false, s);
|
||||
for (size_t s=0; s < strip.getSegmentsNum(); s++) {
|
||||
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, false);
|
||||
}
|
||||
if (realtimeMode && !realtimeOverride && useMainSegmentOnly) { // keep live segment frozen if live
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, true, strip.getMainSegmentId());
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,7 +359,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
realtimeOverride = root[F("lor")] | realtimeOverride;
|
||||
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
|
||||
if (realtimeMode && useMainSegmentOnly) {
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride, strip.getMainSegmentId());
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride);
|
||||
}
|
||||
|
||||
if (root.containsKey("live")) {
|
||||
@ -326,13 +381,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
if (id < 0) {
|
||||
//apply all selected segments
|
||||
//bool didSet = false;
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive()) {
|
||||
if (sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
//didSet = true;
|
||||
}
|
||||
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
|
||||
Segment &sg = strip.getSegment(s);
|
||||
if (sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
//didSet = true;
|
||||
}
|
||||
}
|
||||
//TODO: not sure if it is good idea to change first active but unselected segment
|
||||
@ -342,8 +395,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
} else {
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
for (JsonObject elem : segs)
|
||||
{
|
||||
for (JsonObject elem : segs) {
|
||||
deserializeSegment(elem, it, presetId);
|
||||
it++;
|
||||
}
|
||||
@ -396,7 +448,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
return stateResponse;
|
||||
}
|
||||
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||
{
|
||||
root["id"] = id;
|
||||
if (segmentBounds) {
|
||||
@ -423,7 +475,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
|
||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||
const char *format = strip.hasWhiteChannel() ? PSTR("[%u,%u,%u,%u]") : PSTR("[%u,%u,%u]");
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
{
|
||||
byte segcol[4]; byte* c = segcol;
|
||||
segcol[0] = R(seg.colors[i]);
|
||||
@ -452,6 +504,8 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
root[F("mY")] = seg.getOption(SEG_OPTION_MIRROR_Y);
|
||||
root[F("tp")] = seg.getOption(SEG_OPTION_TRANSPOSED);
|
||||
}
|
||||
root[F("ssim")] = seg.soundSim;
|
||||
root[F("mp12")] = seg.map1D2D;
|
||||
}
|
||||
|
||||
void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segmentBounds)
|
||||
@ -493,9 +547,17 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
|
||||
bool selectedSegmentsOnly = root[F("sc")] | false;
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (selectedSegmentsOnly && !sg.isSelected()) continue;
|
||||
for (size_t s = 0; s < strip.getMaxSegments(); s++) {
|
||||
if (s >= strip.getSegmentsNum()) {
|
||||
if (forPreset && segmentBounds) { //disable segments not part of preset
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
seg0["stop"] = 0;
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
Segment &sg = strip.getSegment(s);
|
||||
if (!forPreset && selectedSegmentsOnly && !sg.isSelected()) continue;
|
||||
if (sg.isActive()) {
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
serializeSegment(seg0, sg, s, forPreset, segmentBounds);
|
||||
@ -518,18 +580,22 @@ void serializeInfo(JsonObject root)
|
||||
leds["fps"] = strip.getFps();
|
||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
leds[F("maxseg")] = strip.getMaxSegments();
|
||||
//leds[F("actseg")] = strip.getActiveSegmentsNum();
|
||||
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (strip.isMatrix) {
|
||||
JsonObject matrix = leds.createNestedObject("matrix");
|
||||
matrix["w"] = strip.matrixWidth;
|
||||
matrix["h"] = strip.matrixHeight;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t totalLC = 0;
|
||||
JsonArray lcarr = leds.createNestedArray(F("seglc"));
|
||||
uint8_t nSegs = strip.getLastActiveSegmentId();
|
||||
for (byte s = 0; s <= nSegs; s++) {
|
||||
size_t nSegs = strip.getSegmentsNum();
|
||||
for (size_t s = 0; s < nSegs; s++) {
|
||||
if (!strip.getSegment(s).isActive()) continue;
|
||||
uint8_t lc = strip.getSegment(s).getLightCapabilities();
|
||||
totalLC |= lc;
|
||||
lcarr.add(lc);
|
||||
@ -577,7 +643,7 @@ void serializeInfo(JsonObject root)
|
||||
root[F("palcount")] = strip.getPaletteCount();
|
||||
|
||||
JsonArray ledmaps = root.createNestedArray(F("maps"));
|
||||
for (uint8_t i=0; i<10; i++) {
|
||||
for (size_t i=0; i<10; i++) {
|
||||
char fileName[16];
|
||||
strcpy_P(fileName, PSTR("/ledmap"));
|
||||
if (i) sprintf(fileName +7, "%d", i);
|
||||
@ -956,7 +1022,7 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
obuf = buffer;
|
||||
olen = 9;
|
||||
|
||||
for (uint16_t i= 0; i < used; i += n)
|
||||
for (size_t i= 0; i < used; i += n)
|
||||
{
|
||||
uint32_t c = strip.getPixelColor(i);
|
||||
uint8_t r = qadd8(W(c), R(c)); //add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
|
@ -8,7 +8,7 @@ void setValuesFromMainSeg() { setValuesFromSegment(strip.getMainSegment
|
||||
void setValuesFromFirstSelectedSeg() { setValuesFromSegment(strip.getFirstSelectedSegId()); }
|
||||
void setValuesFromSegment(uint8_t s)
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(s);
|
||||
Segment& seg = strip.getSegment(s);
|
||||
col[0] = R(seg.colors[0]);
|
||||
col[1] = G(seg.colors[0]);
|
||||
col[2] = B(seg.colors[0]);
|
||||
@ -30,9 +30,9 @@ void applyValuesToSelectedSegs()
|
||||
{
|
||||
// copy of first selected segment to tell if value was updated
|
||||
uint8_t firstSel = strip.getFirstSelectedSegId();
|
||||
WS2812FX::Segment selsegPrev = strip.getSegment(firstSel);
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment selsegPrev = strip.getSegment(firstSel);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue;
|
||||
|
||||
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
||||
@ -41,8 +41,8 @@ void applyValuesToSelectedSegs()
|
||||
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
|
||||
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
||||
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0, i); stateChanged = true;}
|
||||
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1, i); stateChanged = true;}
|
||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
|
||||
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1); stateChanged = true;}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ void parseLxJson(int lxValue, byte segId, bool secondary)
|
||||
} else {
|
||||
DEBUG_PRINT(F("LX: segment "));
|
||||
DEBUG_PRINTLN(segId);
|
||||
strip.getSegment(segId).setColor(secondary, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]), segId);
|
||||
strip.getSegment(segId).setColor(secondary, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,6 @@
|
||||
#ifndef PalettesWLED_h
|
||||
#define PalettesWLED_h
|
||||
|
||||
#define GRADIENT_PALETTE_COUNT 58
|
||||
|
||||
const byte ib_jul01_gp[] PROGMEM = {
|
||||
0, 194, 1, 1,
|
||||
94, 1, 29, 18,
|
||||
|
@ -56,7 +56,8 @@ enum struct PinOwner : uint8_t {
|
||||
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
||||
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
||||
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA, // 0x17 // Usermod "quinled-an-penta.h"
|
||||
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE // 0x1E // Usermod: "audio_reactive.h"
|
||||
UM_BME280 = USERMOD_ID_BME280, // 0x18 // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
|
||||
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE // 0x1E // Usermod "audio_reactive.h"
|
||||
};
|
||||
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
||||
|
||||
|
@ -84,7 +84,7 @@ void handlePresets(bool force)
|
||||
presetToApply = 0; //clear request for preset
|
||||
callModeToApply = 0;
|
||||
|
||||
DEBUG_PRINTLN(F("Applying preset: "));
|
||||
DEBUG_PRINT(F("Applying preset: "));
|
||||
DEBUG_PRINTLN(tmpPreset);
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
@ -86,6 +86,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
Bus::setAutoWhiteMode(request->arg(F("AW")).toInt());
|
||||
strip.setTargetFps(request->arg(F("FR")).toInt());
|
||||
|
||||
bool busesChanged = false;
|
||||
for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) {
|
||||
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
|
||||
@ -98,7 +99,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
char aw[4] = "AW"; aw[2] = 48+s; aw[3] = 0; //auto white mode
|
||||
char wo[4] = "WO"; wo[2] = 48+s; wo[3] = 0; //channel swap
|
||||
if (!request->hasArg(lp)) {
|
||||
DEBUG_PRINTLN(F("No data.")); break;
|
||||
DEBUG_PRINT(F("No data for "));
|
||||
DEBUG_PRINTLN(s);
|
||||
break;
|
||||
}
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
lp[1] = 48+i;
|
||||
@ -118,10 +121,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
awmode = request->arg(aw).toInt();
|
||||
channelSwap = (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) ? request->arg(wo).toInt() : 0;
|
||||
// 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];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode);
|
||||
doInitBusses = true;
|
||||
busesChanged = true;
|
||||
}
|
||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||
|
||||
ColorOrderMap com = {};
|
||||
for (uint8_t s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) {
|
||||
@ -197,6 +202,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
if (t >= 0 && t < 4) strip.paletteBlend = t;
|
||||
t = request->arg(F("BF")).toInt();
|
||||
if (t > 0) briMultiplier = t;
|
||||
|
||||
doInitBusses = busesChanged;
|
||||
}
|
||||
|
||||
//UI
|
||||
@ -547,6 +554,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
//2D panels
|
||||
if (subPage == 10)
|
||||
{
|
||||
@ -570,6 +578,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
strip.setUpMatrix(); // will check limits
|
||||
}
|
||||
#endif
|
||||
|
||||
lastEditTime = millis();
|
||||
if (subPage != 2 && !doReboot) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||
@ -599,17 +608,17 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("SS="));
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t < strip.getMaxSegments()) {
|
||||
if (t < strip.getSegmentsNum()) {
|
||||
selectedSeg = t;
|
||||
singleSegment = true;
|
||||
}
|
||||
}
|
||||
|
||||
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
|
||||
Segment& selseg = strip.getSegment(selectedSeg);
|
||||
pos = req.indexOf(F("SV=")); //segment selected
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t == 2) for (uint8_t i = 0; i < strip.getMaxSegments(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
|
||||
if (t == 2) for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
|
||||
selseg.setOption(SEG_OPTION_SELECTED, t);
|
||||
}
|
||||
|
||||
@ -657,9 +666,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
|
||||
if (pos > 0) {
|
||||
byte segbri = getNumVal(&req, pos);
|
||||
selseg.setOption(SEG_OPTION_ON, segbri, selectedSeg);
|
||||
selseg.setOption(SEG_OPTION_ON, segbri);
|
||||
if (segbri) {
|
||||
selseg.setOpacity(segbri, selectedSeg);
|
||||
selseg.setOpacity(segbri);
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,7 +771,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
||||
uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||
selseg.setColor(2, col2, selectedSeg); // defined above (SS= or main)
|
||||
selseg.setColor(2, col2); // defined above (SS= or main)
|
||||
stateChanged = true;
|
||||
if (!singleSegment) strip.setColor(2, col2); // will set color to all active & selected segments
|
||||
}
|
||||
@ -791,14 +800,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (col0Changed) {
|
||||
stateChanged = true;
|
||||
uint32_t colIn0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]);
|
||||
selseg.setColor(0, colIn0, selectedSeg);
|
||||
selseg.setColor(0, colIn0);
|
||||
if (!singleSegment) strip.setColor(0, colIn0); // will set color to all active & selected segments
|
||||
}
|
||||
|
||||
if (col1Changed) {
|
||||
stateChanged = true;
|
||||
uint32_t colIn1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]);
|
||||
selseg.setColor(1, colIn1, selectedSeg);
|
||||
selseg.setColor(1, colIn1);
|
||||
if (!singleSegment) strip.setColor(1, colIn1); // will set color to all active & selected segments
|
||||
}
|
||||
|
||||
@ -815,8 +824,8 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged);
|
||||
|
||||
// apply to main and all selected segments to prevent #1618.
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all
|
||||
if (fxModeChanged) strip.setMode(i, effectIn);
|
||||
if (speedChanged) seg.speed = speedIn;
|
||||
@ -918,7 +927,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
realtimeOverride = getNumVal(&req, pos);
|
||||
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
|
||||
if (realtimeMode && useMainSegmentOnly) {
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride, strip.getMainSegmentId());
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ void notify(byte callMode, bool followUp)
|
||||
default: return;
|
||||
}
|
||||
byte udpOut[WLEDPACKETSIZE];
|
||||
WS2812FX::Segment& mainseg = strip.getMainSegment();
|
||||
Segment& mainseg = strip.getMainSegment();
|
||||
udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol
|
||||
udpOut[1] = callMode;
|
||||
udpOut[2] = bri;
|
||||
@ -89,12 +89,14 @@ void notify(byte callMode, bool followUp)
|
||||
udpOut[37] = strip.hasCCTBus() ? 0 : 255; //check this is 0 for the next value to be significant
|
||||
udpOut[38] = mainseg.cct;
|
||||
|
||||
udpOut[39] = strip.getMaxSegments();
|
||||
udpOut[39] = strip.getActiveSegmentsNum();
|
||||
udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment)
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment &selseg = strip.getSegment(i);
|
||||
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
|
||||
udpOut[0 +ofs] = i;
|
||||
size_t s = 0, nsegs = strip.getSegmentsNum();
|
||||
for (size_t i = 0; i < nsegs; i++) {
|
||||
Segment &selseg = strip.getSegment(i);
|
||||
if (!selseg.isActive()) continue;
|
||||
uint16_t ofs = 41 + s*UDP_SEG_SIZE; //start of segment offset byte
|
||||
udpOut[0 +ofs] = s;
|
||||
udpOut[1 +ofs] = selseg.start >> 8;
|
||||
udpOut[2 +ofs] = selseg.start & 0xFF;
|
||||
udpOut[3 +ofs] = selseg.stop >> 8;
|
||||
@ -122,6 +124,7 @@ void notify(byte callMode, bool followUp)
|
||||
udpOut[25+ofs] = B(selseg.colors[2]);
|
||||
udpOut[26+ofs] = W(selseg.colors[2]);
|
||||
udpOut[27+ofs] = selseg.cct;
|
||||
++s;
|
||||
}
|
||||
|
||||
//uint16_t offs = SEG_OFFSET;
|
||||
@ -143,20 +146,20 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
if (!realtimeMode && !realtimeOverride) {
|
||||
uint16_t stop, start;
|
||||
if (useMainSegmentOnly) {
|
||||
WS2812FX::Segment& mainseg = strip.getMainSegment();
|
||||
Segment& mainseg = strip.getMainSegment();
|
||||
start = mainseg.start;
|
||||
stop = mainseg.stop;
|
||||
mainseg.setOption(SEG_OPTION_FREEZE, true, strip.getMainSegmentId());
|
||||
mainseg.setOption(SEG_OPTION_FREEZE, true);
|
||||
} else {
|
||||
start = 0;
|
||||
stop = strip.getLengthTotal();
|
||||
}
|
||||
// clear strip/segment
|
||||
for (uint16_t i = start; i < stop; i++) strip.setPixelColor(i,0,0,0,0);
|
||||
for (size_t i = start; i < stop; i++) strip.setPixelColor(i,0,0,0,0);
|
||||
// if WLED was off and using main segment only, freeze non-main segments so they stay off
|
||||
if (useMainSegmentOnly && bri == 0) {
|
||||
for (uint8_t s=0; s < strip.getMaxSegments(); s++) {
|
||||
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, true, s);
|
||||
for (size_t s=0; s < strip.getSegmentsNum(); s++) {
|
||||
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,7 +186,7 @@ void exitRealtime() {
|
||||
realtimeMode = REALTIME_MODE_INACTIVE; // inform UI immediately
|
||||
realtimeIP[0] = 0;
|
||||
if (useMainSegmentOnly) { // unfreeze live segment again
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, false, strip.getMainSegmentId());
|
||||
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, false);
|
||||
}
|
||||
updateInterfaces(CALL_MODE_WS_SEND);
|
||||
}
|
||||
@ -221,7 +224,7 @@ void handleNotifications()
|
||||
if (!udpConnected) return;
|
||||
|
||||
bool isSupp = false;
|
||||
uint16_t packetSize = notifierUdp.parsePacket();
|
||||
size_t packetSize = notifierUdp.parsePacket();
|
||||
if (!packetSize && udp2Connected) {
|
||||
packetSize = notifier2Udp.parsePacket();
|
||||
isSupp = true;
|
||||
@ -241,7 +244,7 @@ void handleNotifications()
|
||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||
uint16_t id = 0;
|
||||
uint16_t totalLen = strip.getLengthTotal();
|
||||
for (uint16_t i = 0; i < packetSize -2; i += 3)
|
||||
for (size_t i = 0; i < packetSize -2; i += 3)
|
||||
{
|
||||
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
||||
id++; if (id >= totalLen) break;
|
||||
@ -275,7 +278,7 @@ void handleNotifications()
|
||||
}
|
||||
|
||||
if (it != Nodes.end()) {
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
for (size_t x = 0; x < 4; x++) {
|
||||
it->second.ip[x] = udpIn[x + 2];
|
||||
}
|
||||
it->second.age = 0; // reset 'age counter'
|
||||
@ -287,7 +290,7 @@ void handleNotifications()
|
||||
it->second.nodeType = udpIn[38];
|
||||
uint32_t build = 0;
|
||||
if (len >= 44)
|
||||
for (byte i=0; i<sizeof(uint32_t); i++)
|
||||
for (size_t i=0; i<sizeof(uint32_t); i++)
|
||||
build |= udpIn[40+i]<<(8*i);
|
||||
it->second.build = build;
|
||||
}
|
||||
@ -339,11 +342,11 @@ void handleNotifications()
|
||||
if (applyEffects && currentPlaylist >= 0) unloadPlaylist();
|
||||
if (version > 10 && (receiveSegmentOptions || receiveSegmentBounds)) {
|
||||
uint8_t numSrcSegs = udpIn[39];
|
||||
for (uint8_t i = 0; i < numSrcSegs; i++) {
|
||||
for (size_t i = 0; i < numSrcSegs; i++) {
|
||||
uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte
|
||||
uint8_t id = udpIn[0 +ofs];
|
||||
if (id > strip.getMaxSegments()) break;
|
||||
WS2812FX::Segment& selseg = strip.getSegment(id);
|
||||
if (id > strip.getSegmentsNum()) break;
|
||||
Segment& selseg = strip.getSegment(id);
|
||||
uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]);
|
||||
uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
||||
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
||||
@ -351,8 +354,8 @@ void handleNotifications()
|
||||
strip.setSegment(id, start, stop, selseg.grouping, selseg.spacing, offset);
|
||||
continue;
|
||||
}
|
||||
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01, id); //only take into account mirrored, selected, on, reversed
|
||||
selseg.setOpacity(udpIn[10+ofs], id);
|
||||
for (size_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
|
||||
selseg.setOpacity(udpIn[10+ofs]);
|
||||
if (applyEffects) {
|
||||
strip.setMode(id, udpIn[11+ofs]);
|
||||
selseg.speed = udpIn[12+ofs];
|
||||
@ -360,10 +363,10 @@ void handleNotifications()
|
||||
selseg.palette = udpIn[14+ofs];
|
||||
}
|
||||
if (receiveNotificationColor || !someSel) {
|
||||
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]), id);
|
||||
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]), id);
|
||||
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]), id);
|
||||
selseg.setCCT(udpIn[27+ofs], id);
|
||||
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]));
|
||||
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]));
|
||||
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]));
|
||||
selseg.setCCT(udpIn[27+ofs]);
|
||||
}
|
||||
//setSegment() also properly resets segments
|
||||
if (receiveSegmentBounds) {
|
||||
@ -377,8 +380,8 @@ void handleNotifications()
|
||||
|
||||
// simple effect sync, applies to all selected segments
|
||||
if (applyEffects && (version < 11 || !receiveSegmentOptions)) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
for (size_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
if (udpIn[8] < strip.getModeCount()) strip.setMode(i, udpIn[8]);
|
||||
seg.speed = udpIn[9];
|
||||
@ -458,7 +461,7 @@ void handleNotifications()
|
||||
|
||||
uint16_t id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
|
||||
uint16_t totalLen = strip.getLengthTotal();
|
||||
for (uint16_t i = 6; i < tpmPayloadFrameSize + 4; i += 3)
|
||||
for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3)
|
||||
{
|
||||
if (id < totalLen)
|
||||
{
|
||||
@ -494,14 +497,14 @@ void handleNotifications()
|
||||
uint16_t totalLen = strip.getLengthTotal();
|
||||
if (udpIn[0] == 1) //warls
|
||||
{
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
for (size_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
|
||||
}
|
||||
} else if (udpIn[0] == 2) //drgb
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -2; i += 3)
|
||||
for (size_t i = 2; i < packetSize -2; i += 3)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
|
||||
@ -510,7 +513,7 @@ void handleNotifications()
|
||||
} else if (udpIn[0] == 3) //drgbw
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
for (size_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
|
||||
@ -519,7 +522,7 @@ void handleNotifications()
|
||||
} else if (udpIn[0] == 4) //dnrgb
|
||||
{
|
||||
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (uint16_t i = 4; i < packetSize -2; i += 3)
|
||||
for (size_t i = 4; i < packetSize -2; i += 3)
|
||||
{
|
||||
if (id >= totalLen) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
@ -528,7 +531,7 @@ void handleNotifications()
|
||||
} else if (udpIn[0] == 5) //dnrgbw
|
||||
{
|
||||
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (uint16_t i = 4; i < packetSize -2; i += 4)
|
||||
for (size_t i = 4; i < packetSize -2; i += 4)
|
||||
{
|
||||
if (id >= totalLen) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
@ -618,7 +621,7 @@ void sendSysInfoUDP()
|
||||
data[0] = 255;
|
||||
data[1] = 1;
|
||||
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
for (size_t x = 0; x < 4; x++) {
|
||||
data[x + 2] = ip[x];
|
||||
}
|
||||
memcpy((byte *)data + 6, serverDescription, 32);
|
||||
@ -632,7 +635,7 @@ void sendSysInfoUDP()
|
||||
data[39] = ip[3]; // unit ID == last IP number
|
||||
|
||||
uint32_t build = VERSION;
|
||||
for (byte i=0; i<sizeof(uint32_t); i++)
|
||||
for (size_t i=0; i<sizeof(uint32_t); i++)
|
||||
data[40+i] = (build>>(8*i)) & 0xFF;
|
||||
|
||||
IPAddress broadcastIP(255, 255, 255, 255);
|
||||
@ -684,15 +687,15 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8
|
||||
case 0: // DDP
|
||||
{
|
||||
// calculate the number of UDP packets we need to send
|
||||
uint16_t channelCount = length * 3; // 1 channel for every R,G,B value
|
||||
uint16_t packetCount = ((channelCount-1) / DDP_CHANNELS_PER_PACKET) +1;
|
||||
size_t channelCount = length * 3; // 1 channel for every R,G,B value
|
||||
size_t packetCount = ((channelCount-1) / DDP_CHANNELS_PER_PACKET) +1;
|
||||
|
||||
// there are 3 channels per RGB pixel
|
||||
uint32_t channel = 0; // TODO: allow specifying the start channel
|
||||
// the current position in the buffer
|
||||
uint16_t bufferOffset = 0;
|
||||
size_t bufferOffset = 0;
|
||||
|
||||
for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) {
|
||||
for (size_t currentPacket = 0; currentPacket < packetCount; currentPacket++) {
|
||||
if (sequenceNumber > 15) sequenceNumber = 0;
|
||||
|
||||
if (!ddpUdp.beginPacket(client, DDP_DEFAULT_PORT)) { // port defined in ESPAsyncE131.h
|
||||
@ -701,10 +704,10 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8
|
||||
}
|
||||
|
||||
// the amount of data is AFTER the header in the current packet
|
||||
uint16_t packetSize = DDP_CHANNELS_PER_PACKET;
|
||||
size_t packetSize = DDP_CHANNELS_PER_PACKET;
|
||||
|
||||
uint8_t flags = DDP_FLAGS1_VER1;
|
||||
if (currentPacket == (packetCount - 1)) {
|
||||
if (currentPacket == (packetCount - 1U)) {
|
||||
// last packet, set the push flag
|
||||
// TODO: determine if we want to send an empty push packet to each destination after sending the pixel data
|
||||
flags = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH;
|
||||
@ -729,7 +732,7 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8
|
||||
|
||||
// write the colors, the write write(const uint8_t *buffer, size_t size)
|
||||
// function is just a loop internally too
|
||||
for (uint16_t i = 0; i < packetSize; i += 3) {
|
||||
for (size_t i = 0; i < packetSize; i += 3) {
|
||||
ddpUdp.write(scale8(buffer[bufferOffset++], bri)); // R
|
||||
ddpUdp.write(scale8(buffer[bufferOffset++], bri)); // G
|
||||
ddpUdp.write(scale8(buffer[bufferOffset++], bri)); // B
|
||||
|
@ -59,5 +59,3 @@ bool UsermodManager::add(Usermod* um)
|
||||
ums[numMods++] = um;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte UsermodManager::getModCount() {return numMods;}
|
248
wled00/util.cpp
248
wled00/util.cpp
@ -238,14 +238,13 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
||||
char lineBuffer[256];
|
||||
//strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode])));
|
||||
strcpy_P(lineBuffer, strip.getModeData(mode));
|
||||
if (strlen(lineBuffer) > 0) {
|
||||
size_t j = 0;
|
||||
for (; j < maxLen; j++) {
|
||||
if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') break;
|
||||
dest[j] = lineBuffer[j];
|
||||
}
|
||||
dest[j] = 0; // terminate string
|
||||
size_t len = strlen(lineBuffer);
|
||||
size_t j = 0;
|
||||
for (; j < maxLen && j < len; j++) {
|
||||
if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') break;
|
||||
dest[j] = lineBuffer[j];
|
||||
}
|
||||
dest[j] = 0; // terminate string
|
||||
return strlen(dest);
|
||||
} else return 0;
|
||||
}
|
||||
@ -282,7 +281,7 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
||||
|
||||
|
||||
// extracts effect slider data (1st group after @)
|
||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen)
|
||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var)
|
||||
{
|
||||
dest[0] = '\0'; // start by clearing buffer
|
||||
|
||||
@ -292,30 +291,50 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
||||
int16_t start = lineBuffer.indexOf('@');
|
||||
int16_t stop = lineBuffer.indexOf(';', start);
|
||||
if (start>0 && stop>0) {
|
||||
String names = lineBuffer.substring(start+1, stop);
|
||||
int16_t nameBegin = 0, nameEnd;
|
||||
for (size_t i=0; i<=slider; i++) {
|
||||
const char *tmpstr;
|
||||
dest[0] = '\0'; //clear dest buffer
|
||||
if (i > 0 && nameBegin == 0) break; // there are no more names
|
||||
nameEnd = names.indexOf(',', nameBegin);
|
||||
if (names.charAt(nameBegin) == '!') {
|
||||
switch (i) {
|
||||
case 0: tmpstr = PSTR("FX Speed"); break;
|
||||
case 1: tmpstr = PSTR("FX Intensity"); break;
|
||||
case 2: tmpstr = PSTR("FX Custom 1"); break;
|
||||
case 3: tmpstr = PSTR("FX Custom 2"); break;
|
||||
case 4: tmpstr = PSTR("FX Custom 3"); break;
|
||||
default: tmpstr = PSTR("FX Custom"); break;
|
||||
String names = lineBuffer.substring(start, stop); // include @
|
||||
int16_t nameBegin = 1, nameEnd, nameDefault;
|
||||
if (slider < 10) {
|
||||
for (size_t i=0; i<=slider; i++) {
|
||||
const char *tmpstr;
|
||||
dest[0] = '\0'; //clear dest buffer
|
||||
if (nameBegin == 0) break; // there are no more names
|
||||
nameEnd = names.indexOf(',', nameBegin);
|
||||
if (i == slider) {
|
||||
nameDefault = names.indexOf('=', nameBegin); // find default value
|
||||
if (nameDefault > 0 && var && ((nameEnd>0 && nameDefault<nameEnd) || nameEnd<0)) {
|
||||
*var = (uint8_t)atoi(names.substring(nameDefault+1).c_str());
|
||||
}
|
||||
if (names.charAt(nameBegin) == '!') {
|
||||
switch (slider) {
|
||||
case 0: tmpstr = PSTR("FX Speed"); break;
|
||||
case 1: tmpstr = PSTR("FX Intensity"); break;
|
||||
case 2: tmpstr = PSTR("FX Custom 1"); break;
|
||||
case 3: tmpstr = PSTR("FX Custom 2"); break;
|
||||
case 4: tmpstr = PSTR("FX Custom 3"); break;
|
||||
default: tmpstr = PSTR("FX Custom"); break;
|
||||
}
|
||||
} else {
|
||||
if (nameEnd<0) tmpstr = names.substring(nameBegin).c_str(); // did not find ",", last name?
|
||||
else tmpstr = names.substring(nameBegin, nameEnd).c_str();
|
||||
}
|
||||
strlcpy(dest, tmpstr, maxLen); // copy the name into buffer (replacing previous)
|
||||
}
|
||||
nameBegin = nameEnd+1; // next name (if "," is not found it will be 0)
|
||||
} // next slider
|
||||
} else if (slider == 255) {
|
||||
// palette
|
||||
strlcpy(dest, "pal", maxLen);
|
||||
names = lineBuffer.substring(stop+1); // stop has index of color slot names
|
||||
nameBegin = names.indexOf(';'); // look for palette
|
||||
if (nameBegin >= 0) {
|
||||
nameEnd = names.indexOf(';', nameBegin+1);
|
||||
if (!isdigit(names[nameBegin+1])) nameBegin = names.indexOf('=', nameBegin+1); // look for default value
|
||||
if (nameEnd >= 0 && nameBegin > nameEnd) nameBegin = -1;
|
||||
if (nameBegin >= 0 && var) {
|
||||
*var = (uint8_t)atoi(names.substring(nameBegin+1).c_str());
|
||||
}
|
||||
} else {
|
||||
if (nameEnd<0) tmpstr = names.substring(nameBegin).c_str(); // did not find ",", last name?
|
||||
else tmpstr = names.substring(nameBegin, nameEnd).c_str();
|
||||
}
|
||||
strncpy(dest, tmpstr, maxLen); // copy the name into buffer (replacing previous)
|
||||
nameBegin = nameEnd+1; // next name (if "," is not found it will be 0)
|
||||
} // next slider
|
||||
|
||||
}
|
||||
// we have slider name (including default value) in the dest buffer
|
||||
for (size_t i=0; i<strlen(dest); i++) if (dest[i]=='=') { dest[i]='\0'; break; } // truncate default value
|
||||
|
||||
@ -325,6 +344,7 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
||||
case 0: strncpy_P(dest, PSTR("FX Speed"), maxLen); break;
|
||||
case 1: strncpy_P(dest, PSTR("FX Intensity"), maxLen); break;
|
||||
}
|
||||
dest[maxLen] = '\0'; // strncpy does not necessarily null terminate string
|
||||
}
|
||||
}
|
||||
return strlen(dest);
|
||||
@ -333,6 +353,23 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
||||
}
|
||||
|
||||
|
||||
int16_t extractModeDefaults(uint8_t mode, const char *segVar)
|
||||
{
|
||||
if (mode < strip.getModeCount()) {
|
||||
String lineBuffer = strip.getModeData(mode);
|
||||
if (lineBuffer.length() > 0) {
|
||||
int16_t start = lineBuffer.lastIndexOf(';');
|
||||
if (start<0) return -1;
|
||||
|
||||
int16_t stop = lineBuffer.indexOf(segVar, start+1);
|
||||
if (stop<0) return -1;
|
||||
return atoi(lineBuffer.substring(stop+strlen(segVar)+1).c_str());
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||
uint8_t x;
|
||||
uint16_t crc = 0xFFFF;
|
||||
@ -344,3 +381,154 @@ uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Begin simulateSound (to enable audio enhanced effects to display something)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Currently 4 types defined, to be fine tuned and new types added
|
||||
typedef enum UM_SoundSimulations {
|
||||
UMS_BeatSin = 0,
|
||||
UMS_WeWillRockYou,
|
||||
UMS_10_3,
|
||||
UMS_14_3
|
||||
} um_soundSimulations_t;
|
||||
|
||||
// this is still work in progress
|
||||
um_data_t* simulateSound(uint8_t simulationId)
|
||||
{
|
||||
static float sampleAvg;
|
||||
static uint8_t soundAgc;
|
||||
static float sampleAgc;
|
||||
static int16_t sampleRaw;
|
||||
static int16_t rawSampleAgc;
|
||||
static uint8_t samplePeak;
|
||||
static float FFT_MajorPeak;
|
||||
static float FFT_Magnitude;
|
||||
static uint8_t maxVol;
|
||||
static uint8_t binNum;
|
||||
static float multAgc;
|
||||
|
||||
float sampleGain;
|
||||
uint8_t soundSquelch;
|
||||
uint8_t inputLevel;
|
||||
|
||||
//arrays
|
||||
uint8_t *fftResult;
|
||||
uint8_t *myVals;
|
||||
float *fftBin;
|
||||
|
||||
static um_data_t* um_data = nullptr;
|
||||
|
||||
if (!um_data) {
|
||||
//claim storage for arrays
|
||||
fftResult = (uint8_t *)malloc(sizeof(uint8_t) * 16);
|
||||
myVals = (uint8_t *)malloc(sizeof(uint8_t) * 32);
|
||||
fftBin = (float *)malloc(sizeof(float) * 256); // not used (for debugging purposes)
|
||||
|
||||
// initialize um_data pointer structure
|
||||
// NOTE!!!
|
||||
// This may change as AudioReactive usermod may change
|
||||
um_data = new um_data_t;
|
||||
um_data->u_size = 18;
|
||||
um_data->u_type = new um_types_t[um_data->u_size];
|
||||
um_data->u_data = new void*[um_data->u_size];
|
||||
um_data->u_data[ 0] = &sampleAvg;
|
||||
um_data->u_data[ 1] = &soundAgc;
|
||||
um_data->u_data[ 2] = &sampleAgc;
|
||||
um_data->u_data[ 3] = &sampleRaw;
|
||||
um_data->u_data[ 4] = &rawSampleAgc;
|
||||
um_data->u_data[ 5] = &samplePeak;
|
||||
um_data->u_data[ 6] = &FFT_MajorPeak;
|
||||
um_data->u_data[ 7] = &FFT_Magnitude;
|
||||
um_data->u_data[ 8] = fftResult;
|
||||
um_data->u_data[ 9] = &maxVol;
|
||||
um_data->u_data[10] = &binNum;
|
||||
um_data->u_data[11] = &multAgc;
|
||||
um_data->u_data[14] = myVals; //*used (only once, Pixels)
|
||||
um_data->u_data[13] = &sampleGain;
|
||||
um_data->u_data[15] = &soundSquelch;
|
||||
um_data->u_data[16] = fftBin; //only used in binmap
|
||||
um_data->u_data[17] = &inputLevel;
|
||||
} else {
|
||||
// get arrays from um_data
|
||||
fftResult = (uint8_t*)um_data->u_data[8];
|
||||
myVals = (uint8_t*)um_data->u_data[14];
|
||||
fftBin = (float*)um_data->u_data[16];
|
||||
}
|
||||
|
||||
uint32_t ms = millis();
|
||||
|
||||
switch (simulationId) {
|
||||
default:
|
||||
case UMS_BeatSin:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = beatsin8(120 / (i+1), 0, 255);
|
||||
// fftResult[i] = (beatsin8(120, 0, 255) + (256/16 * i)) % 256;
|
||||
sampleAvg = fftResult[8];
|
||||
break;
|
||||
case UMS_WeWillRockYou:
|
||||
if (ms%2000 < 200) {
|
||||
sampleAvg = random8(255);
|
||||
for (int i = 0; i<5; i++)
|
||||
fftResult[i] = random8(255);
|
||||
}
|
||||
else if (ms%2000 < 400) {
|
||||
sampleAvg = 0;
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = 0;
|
||||
}
|
||||
else if (ms%2000 < 600) {
|
||||
sampleAvg = random8(255);
|
||||
for (int i = 5; i<11; i++)
|
||||
fftResult[i] = random8(255);
|
||||
}
|
||||
else if (ms%2000 < 800) {
|
||||
sampleAvg = 0;
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = 0;
|
||||
}
|
||||
else if (ms%2000 < 1000) {
|
||||
sampleAvg = random8(255);
|
||||
for (int i = 11; i<16; i++)
|
||||
fftResult[i] = random8(255);
|
||||
}
|
||||
else {
|
||||
sampleAvg = 0;
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = 0;
|
||||
}
|
||||
break;
|
||||
case UMS_10_3:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
||||
sampleAvg = fftResult[8];
|
||||
break;
|
||||
case UMS_14_3:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
|
||||
sampleAvg = fftResult[8];
|
||||
break;
|
||||
}
|
||||
|
||||
//derive other vars from sampleAvg
|
||||
|
||||
//sampleAvg = mapf(sampleAvg, 0, 255, 0, 255); // help me out here
|
||||
soundAgc = 0; //only avg in simulations
|
||||
sampleAgc = sampleAvg;
|
||||
sampleRaw = sampleAvg;
|
||||
sampleRaw = map(sampleRaw, 50, 190, 0, 224);
|
||||
rawSampleAgc = sampleAvg;
|
||||
samplePeak = random8() > 250;
|
||||
FFT_MajorPeak = sampleAvg;
|
||||
FFT_Magnitude = sampleAvg;
|
||||
multAgc = sampleAvg;
|
||||
myVals[millis()%32] = sampleAvg; // filling values semi randomly (why?)
|
||||
sampleGain = 40;
|
||||
soundSquelch = 10;
|
||||
maxVol = 10; // this gets feedback fro UI
|
||||
binNum = 8; // this gets feedback fro UI
|
||||
inputLevel = 128; // this gets feedback fro UI
|
||||
|
||||
return um_data;
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ void WLED::loop()
|
||||
if (stripMillis > maxStripMillis) maxStripMillis = stripMillis;
|
||||
#endif
|
||||
}
|
||||
|
||||
yield();
|
||||
#ifdef ESP8266
|
||||
MDNS.update();
|
||||
@ -692,6 +693,7 @@ void WLED::handleConnection()
|
||||
DEBUG_PRINT(F("Heap too low! "));
|
||||
DEBUG_PRINTLN(heap);
|
||||
forceReconnect = true;
|
||||
strip.purgeSegments(); // remove inactive segments from memory
|
||||
}
|
||||
lastHeap = heap;
|
||||
heapTime = now;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2206281
|
||||
#define VERSION 2207271
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -152,19 +152,19 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
||||
#define PSRAMDynamicJsonDocument DynamicJsonDocument
|
||||
#endif
|
||||
|
||||
#include "const.h"
|
||||
#include "fcn_declare.h"
|
||||
#include "html_ui.h"
|
||||
#ifdef WLED_ENABLE_SIMPLE_UI
|
||||
#include "html_simple.h"
|
||||
#include "html_simple.h"
|
||||
#endif
|
||||
#include "html_settings.h"
|
||||
#include "html_other.h"
|
||||
#include "FX.h"
|
||||
#include "ir_codes.h"
|
||||
#include "const.h"
|
||||
#include "NodeStruct.h"
|
||||
#include "pin_manager.h"
|
||||
#include "bus_manager.h"
|
||||
#include "FX.h"
|
||||
|
||||
#ifndef CLIENT_SSID
|
||||
#define CLIENT_SSID DEFAULT_CLIENT_SSID
|
||||
|
@ -418,7 +418,7 @@ void deEEP() {
|
||||
segObj[F("ix")] = EEPROM.read(i+16);
|
||||
segObj["pal"] = EEPROM.read(i+17);
|
||||
} else {
|
||||
WS2812FX::Segment* seg = strip.getSegments();
|
||||
Segment* seg = strip.getSegments();
|
||||
memcpy(seg, EEPROM.getDataPtr() +i+2, 240);
|
||||
if (ver == 2) { //versions before 2004230 did not have opacity
|
||||
for (byte j = 0; j < strip.getMaxSegments(); j++)
|
||||
|
@ -297,8 +297,8 @@ void initServer()
|
||||
DEBUG_PRINTLN(F("Update Success"));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Update Failed"));
|
||||
WLED::instance().enableWatchdog();
|
||||
usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
|
||||
WLED::instance().enableWatchdog();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -58,6 +58,10 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
if (verboseResponse) {
|
||||
sendDataWs(client);
|
||||
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
|
||||
} else {
|
||||
// we have to send something back otherwise WS connection closes
|
||||
client->text(F("{\"success\":true}"));
|
||||
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -96,8 +100,6 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
if (!ws.count()) return;
|
||||
AsyncWebSocketMessageBuffer * buffer;
|
||||
|
||||
while (strip.isUpdating()) yield();
|
||||
|
||||
if (!requestJSONBufferLock(12)) return;
|
||||
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
|
@ -308,9 +308,15 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
// set limits
|
||||
oappend(SET_F("bLimits("));
|
||||
#ifdef ESP32
|
||||
// requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
||||
if (usermods.lookup(USERMOD_ID_AUDIOREACTIVE))
|
||||
oappend(itoa(WLED_MAX_BUSSES-2,nS,10)); // prevent use of I2S buses if audio installed
|
||||
else
|
||||
#endif
|
||||
oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(",");
|
||||
oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(",");
|
||||
oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(",");
|
||||
oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(",");
|
||||
oappend(itoa(MAX_LEDS,nS,10));
|
||||
oappend(SET_F(");"));
|
||||
|
||||
@ -636,6 +642,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
if (subPage == 10) // 2D matrices
|
||||
{
|
||||
sappend('v',SET_F("SOMP"),strip.isMatrix);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
oappend(SET_F("resetPanels();"));
|
||||
if (strip.isMatrix) {
|
||||
sappend('v',SET_F("PH"),strip.panelH);
|
||||
@ -660,5 +667,8 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
pO[l] = 'S'; sappend('c',pO,strip.panel[i].serpentine);
|
||||
}
|
||||
}
|
||||
#else
|
||||
oappend(SET_F("gId(\"somp\").remove(1);")); // remove 2D option from dropdown
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user