mirror of
https://github.com/wled/WLED.git
synced 2026-04-22 15:12:45 +00:00
Compare commits
99 Commits
v0.12.0-b5
...
0.12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a52386e6ad | ||
|
|
70546cd2ec | ||
|
|
a7c99cbbd2 | ||
|
|
40780ccec7 | ||
|
|
7078c91f7d | ||
|
|
0e2168392c | ||
|
|
380006c9d8 | ||
|
|
4127882e5f | ||
|
|
5f17d30973 | ||
|
|
6ace46eece | ||
|
|
37cab07295 | ||
|
|
cfeb88f649 | ||
|
|
7ce197e0c8 | ||
|
|
f93b1167f1 | ||
|
|
152ca63529 | ||
|
|
2e8d5311a5 | ||
|
|
23b5fd1c12 | ||
|
|
7a8ba7d47d | ||
|
|
1a509cf3e0 | ||
|
|
9848f9613c | ||
|
|
93cefb88f5 | ||
|
|
7132e1fee1 | ||
|
|
e70e1b8ad7 | ||
|
|
77d8a8e43d | ||
|
|
0b75a7d0d3 | ||
|
|
f6772eaf59 | ||
|
|
7ac5abe7f8 | ||
|
|
157e6b2a33 | ||
|
|
a385ea7c52 | ||
|
|
c58a3c41d8 | ||
|
|
0a7df86f3f | ||
|
|
f8df7ebb7c | ||
|
|
60503c31fb | ||
|
|
77220e24dd | ||
|
|
3c25e11c5f | ||
|
|
be2ffc31b2 | ||
|
|
adfb24ce02 | ||
|
|
e6d50f94ee | ||
|
|
520798bfa6 | ||
|
|
e539a36ae7 | ||
|
|
bfab2d405b | ||
|
|
df38f00cf2 | ||
|
|
a30ce1c44d | ||
|
|
baf4a241a2 | ||
|
|
c59e792178 | ||
|
|
e6a99c1d33 | ||
|
|
3548628c2c | ||
|
|
bb84157a21 | ||
|
|
eb10aa8c97 | ||
|
|
07428922c3 | ||
|
|
0f7e22d8b7 | ||
|
|
caae57d960 | ||
|
|
f91384596c | ||
|
|
cb38976162 | ||
|
|
4c5c4d1700 | ||
|
|
e3fabe92bd | ||
|
|
142740f080 | ||
|
|
09e51c2399 | ||
|
|
0892eb271d | ||
|
|
536be76ecb | ||
|
|
6bfdf0eb4d | ||
|
|
8320ed5a92 | ||
|
|
43677685bb | ||
|
|
61e0aa9845 | ||
|
|
34eee005a8 | ||
|
|
6fa136da0c | ||
|
|
b5abc6c724 | ||
|
|
f74a45a33e | ||
|
|
0a1d04495d | ||
|
|
49dee560fd | ||
|
|
dfb3dfb74d | ||
|
|
c4689c3bcc | ||
|
|
83452d73bc | ||
|
|
e5417d12ca | ||
|
|
6e19e6f0a0 | ||
|
|
071281c13a | ||
|
|
61101987f9 | ||
|
|
a057e50684 | ||
|
|
5f3dc660c8 | ||
|
|
51ead2f6bd | ||
|
|
d433b25627 | ||
|
|
bd7671c07e | ||
|
|
847178b7be | ||
|
|
a899ea8b4d | ||
|
|
7b83b99ac9 | ||
|
|
c11acb6308 | ||
|
|
d76103eb76 | ||
|
|
779f984a30 | ||
|
|
9c55017191 | ||
|
|
c6f575d8d3 | ||
|
|
2c0c22dbf3 | ||
|
|
73a99a7dea | ||
|
|
3c81337630 | ||
|
|
3f41ba6bdf | ||
|
|
2812f61957 | ||
|
|
f23cee17eb | ||
|
|
f24fcfca69 | ||
|
|
d60506a75d | ||
|
|
77dee439e6 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,7 +1,18 @@
|
||||
## WLED changelog
|
||||
|
||||
#### Build 2104020
|
||||
|
||||
- Allow clearing button/IR/relay pin on platforms that don't support negative numbers
|
||||
- Removed AUX pin
|
||||
- Hid some easter eggs, only to be found at easter
|
||||
|
||||
### Development versions between 0.11.1 and 0.12.0 releases
|
||||
|
||||
#### Build 2103310
|
||||
|
||||
- Version bump to 0.12.0 "Hikari"
|
||||
- Fixed LED settings submission in iOS app
|
||||
|
||||
#### Build 2103300
|
||||
|
||||
- Version bump to 0.12.0-b5 "Hikari"
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.11.1",
|
||||
"version": "0.12.0-b3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.12.0-b5",
|
||||
"version": "0.12.0",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
||||
@@ -344,65 +344,6 @@ build_flags = ${common.build_flags_esp8266} -D LEDPIN=12 -D IRPIN=-1 -D RLYPIN=2
|
||||
# custom board configurations
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:custom_LEDPIN_4]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=4 -D IRPIN=5
|
||||
|
||||
[env:custom_LEDPIN_16]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=16
|
||||
|
||||
|
||||
[env:custom_LEDPIN_3]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
|
||||
|
||||
[env:custom_APA102]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_APA102
|
||||
|
||||
[env:custom_WS2801]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_WS2801
|
||||
|
||||
[env:custom32_LEDPIN_16]
|
||||
board = esp32dev
|
||||
platform = espressif32@3.2
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:custom32_APA102]
|
||||
board = esp32dev
|
||||
platform = espressif32@3.2
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D USE_APA102
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:custom32_TOUCHPIN_T0]
|
||||
board = esp32dev
|
||||
platform = espressif32@3.2
|
||||
|
||||
@@ -21,6 +21,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
|
||||
- Segments to set different effects and colors to parts of the LEDs
|
||||
- Settings page - configuration over network
|
||||
- Access Point and station mode - automatic failsafe AP
|
||||
- Up to 10 LED outputs per instance
|
||||
- Support for RGBW strips
|
||||
- Up to 250 user presets to save and load colors/effects easily, supports cycling through them.
|
||||
- Presets can be used to automatically execute API calls
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef PIR_SENSOR_PIN
|
||||
// compatible with QuinLED-Dig-Uno
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define PIR_SENSOR_PIN 23 // Q4
|
||||
#else //ESP8266 boards
|
||||
#define PIR_SENSOR_PIN 13 // Q4 (D7 on D1 mini)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This usermod handles PIR sensor states.
|
||||
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
||||
@@ -24,6 +33,9 @@
|
||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||
*/
|
||||
|
||||
// MQTT topic for sensor values
|
||||
const char MQTT_TOPIC[] = "/motion";
|
||||
|
||||
class PIRsensorSwitch : public Usermod
|
||||
{
|
||||
public:
|
||||
@@ -60,7 +72,7 @@ public:
|
||||
|
||||
private:
|
||||
// PIR sensor pin
|
||||
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
|
||||
int8_t PIRsensorPin = PIR_SENSOR_PIN;
|
||||
// notification mode for colorUpdated()
|
||||
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE
|
||||
// delay before switch off after the sensor state goes LOW
|
||||
@@ -107,6 +119,17 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void publishMqtt(const char* state)
|
||||
{
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr){
|
||||
char subuf[64];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, MQTT_TOPIC);
|
||||
mqtt->publish(subuf, 0, true, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and update PIR sensor state.
|
||||
* Initilize/reset switch off timer
|
||||
@@ -121,6 +144,7 @@ private:
|
||||
{
|
||||
m_offTimerStart = 0;
|
||||
switchStrip(true);
|
||||
publishMqtt("on");
|
||||
}
|
||||
else if (bri != 0)
|
||||
{
|
||||
@@ -143,6 +167,7 @@ private:
|
||||
if (m_PIRenabled == true)
|
||||
{
|
||||
switchStrip(false);
|
||||
publishMqtt("off");
|
||||
}
|
||||
m_offTimerStart = 0;
|
||||
return true;
|
||||
@@ -159,12 +184,19 @@ public:
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
if (m_PIRenabled)
|
||||
{
|
||||
// assign interrupt function and set CHANGE mode
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (!pinManager.allocatePin(PIRsensorPin,false)) {
|
||||
PIRsensorPin = -1; // allocation failed
|
||||
m_PIRenabled = false;
|
||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||
} else {
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
if (m_PIRenabled)
|
||||
{
|
||||
// assign interrupt function and set CHANGE mode
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,8 +305,8 @@ after <input type=\"number\" min=\"1\" max=\"720\" value=\"";
|
||||
*/
|
||||
void addToJsonState(JsonObject &root)
|
||||
{
|
||||
root["PIRenabled"] = m_PIRenabled;
|
||||
root["PIRoffSec"] = (m_switchOffDelay / 1000);
|
||||
root[F("PIRenabled")] = m_PIRenabled;
|
||||
root[F("PIRoffSec")] = (m_switchOffDelay / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,15 +317,37 @@ after <input type=\"number\" min=\"1\" max=\"720\" value=\"";
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root)
|
||||
{
|
||||
if (root["PIRoffSec"] != nullptr)
|
||||
if (root[F("PIRoffSec")] != nullptr)
|
||||
{
|
||||
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
|
||||
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root[F("PIRoffSec")].as<unsigned long>())));
|
||||
m_updateConfig = true;
|
||||
}
|
||||
|
||||
if (root["PIRenabled"] != nullptr)
|
||||
if (root[F("pin")] != nullptr)
|
||||
{
|
||||
if (root["PIRenabled"] && !m_PIRenabled)
|
||||
int8_t pin = (int)root[F("pin")];
|
||||
// check if pin is OK
|
||||
if (pin != PIRsensorPin && pin>=0 && pinManager.allocatePin(pin,false)) {
|
||||
// deallocate old pin
|
||||
pinManager.deallocatePin(PIRsensorPin);
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(pin, INPUT_PULLUP);
|
||||
if (m_PIRenabled)
|
||||
{
|
||||
// remove old ISR
|
||||
detachInterrupt(PIRsensorPin);
|
||||
// assign interrupt function and set CHANGE mode
|
||||
attachInterrupt(digitalPinToInterrupt(pin), ISR_PIRstateChange, CHANGE);
|
||||
newPIRsensorState(true, true);
|
||||
}
|
||||
PIRsensorPin = pin;
|
||||
m_updateConfig = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (root[F("PIRenabled")] != nullptr)
|
||||
{
|
||||
if (root[F("PIRenabled")] && !m_PIRenabled)
|
||||
{
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
newPIRsensorState(true, true);
|
||||
@@ -302,7 +356,7 @@ after <input type=\"number\" min=\"1\" max=\"720\" value=\"";
|
||||
{
|
||||
detachInterrupt(PIRsensorPin);
|
||||
}
|
||||
m_PIRenabled = root["PIRenabled"];
|
||||
m_PIRenabled = root[F("PIRenabled")];
|
||||
m_updateConfig = true;
|
||||
}
|
||||
}
|
||||
@@ -312,19 +366,24 @@ after <input type=\"number\" min=\"1\" max=\"720\" value=\"";
|
||||
*/
|
||||
void addToConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject("PIRsensorSwitch");
|
||||
top["PIRenabled"] = m_PIRenabled;
|
||||
top["PIRoffSec"] = m_switchOffDelay;
|
||||
JsonObject top = root.createNestedObject(F("PIRsensorSwitch"));
|
||||
top[F("PIRenabled")] = m_PIRenabled;
|
||||
top[F("PIRoffSec")] = m_switchOffDelay;
|
||||
top[F("pin")] = PIRsensorPin;
|
||||
}
|
||||
|
||||
/**
|
||||
* restore the changeable values
|
||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||
*/
|
||||
void readFromConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root["PIRsensorSwitch"];
|
||||
m_PIRenabled = (top["PIRenabled"] != nullptr ? top["PIRenabled"] : true);
|
||||
m_switchOffDelay = top["PIRoffSec"] | m_switchOffDelay;
|
||||
JsonObject top = root[F("PIRsensorSwitch")];
|
||||
if (!top.isNull() && top[F("pin")] != nullptr) {
|
||||
PIRsensorPin = (int)top[F("pin")];
|
||||
}
|
||||
m_PIRenabled = (top[F("PIRenabled")] != nullptr ? top[F("PIRenabled")] : true);
|
||||
m_switchOffDelay = top[F("PIRoffSec")] | m_switchOffDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
#include <DallasTemperature.h> //DS18B20
|
||||
|
||||
//Pin defaults for QuinLed Dig-Uno
|
||||
//Pin defaults for QuinLed Dig-Uno if not overriden
|
||||
#ifndef TEMPERATURE_PIN
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define TEMPERATURE_PIN 18
|
||||
#else //ESP8266 boards
|
||||
#define TEMPERATURE_PIN 14
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define TEMPERATURE_PIN 18
|
||||
#else //ESP8266 boards
|
||||
#define TEMPERATURE_PIN 14
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// the frequency to check temperature, 1 minute
|
||||
@@ -20,19 +20,22 @@
|
||||
|
||||
// how many seconds after boot to take first measurement, 20 seconds
|
||||
#ifndef USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT
|
||||
#define USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT 20000
|
||||
#define USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT 20000
|
||||
#endif
|
||||
|
||||
OneWire oneWire(TEMPERATURE_PIN);
|
||||
DallasTemperature sensor(&oneWire);
|
||||
|
||||
class UsermodTemperature : public Usermod {
|
||||
private:
|
||||
OneWire *oneWire;
|
||||
DallasTemperature *sensor;
|
||||
// The device's unique 64-bit serial code stored in on-board ROM.
|
||||
// Reading directly from the sensor device address is faster than
|
||||
// reading from index. When reading by index, DallasTemperature
|
||||
// must first look up the device address at the specified index.
|
||||
DeviceAddress sensorDeviceAddress;
|
||||
// GPIO pin used for sensor (with a default compile-time fallback)
|
||||
int8_t temperaturePin = TEMPERATURE_PIN;
|
||||
// measurement unit (true==°C, false==°F)
|
||||
bool degC = true;
|
||||
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
||||
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT);
|
||||
// last time requestTemperatures was called
|
||||
@@ -51,21 +54,19 @@ class UsermodTemperature : public Usermod {
|
||||
bool disabled = false;
|
||||
|
||||
void requestTemperatures() {
|
||||
// there is requestTemperaturesByAddress however it
|
||||
// appears to do more work,
|
||||
// there is requestTemperaturesByAddress however it
|
||||
// appears to do more work,
|
||||
// TODO: measure exection time difference
|
||||
sensor.requestTemperatures();
|
||||
sensor->requestTemperatures();
|
||||
lastTemperaturesRequest = millis();
|
||||
waitingForConversion = true;
|
||||
}
|
||||
|
||||
void getTemperature() {
|
||||
if (strip.isUpdating()) return;
|
||||
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||
temperature = sensor.getTempC(sensorDeviceAddress);
|
||||
#else
|
||||
temperature = sensor.getTempF(sensorDeviceAddress);
|
||||
#endif
|
||||
|
||||
if (degC) temperature = sensor->getTempC(sensorDeviceAddress);
|
||||
else temperature = sensor->getTempF(sensorDeviceAddress);
|
||||
|
||||
lastMeasurement = millis();
|
||||
waitingForConversion = false;
|
||||
@@ -76,21 +77,29 @@ class UsermodTemperature : public Usermod {
|
||||
|
||||
|
||||
void setup() {
|
||||
sensor.begin();
|
||||
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (!pinManager.allocatePin(temperaturePin,false)) {
|
||||
temperaturePin = -1; // allocation failed
|
||||
DEBUG_PRINTLN(F("Temperature pin allocation failed."));
|
||||
} else {
|
||||
oneWire = new OneWire(temperaturePin);
|
||||
sensor = new DallasTemperature(oneWire);
|
||||
if (sensor) sensor->begin();
|
||||
else
|
||||
DEBUG_PRINTLN(F("Temperature sensor allocation failed."));
|
||||
}
|
||||
|
||||
// get the unique 64-bit serial code stored in on-board ROM
|
||||
// if getAddress returns false, the sensor was not found
|
||||
disabled = !sensor.getAddress(sensorDeviceAddress, 0);
|
||||
disabled = (temperaturePin==-1) || !sensor->getAddress(sensorDeviceAddress, 0);
|
||||
|
||||
if (!disabled) {
|
||||
DEBUG_PRINTLN(F("Dallas Temperature found"));
|
||||
// set the resolution for this specific device
|
||||
sensor.setResolution(sensorDeviceAddress, 9, true);
|
||||
sensor->setResolution(sensorDeviceAddress, 9, true);
|
||||
// do not block waiting for reading
|
||||
sensor.setWaitForConversion(false);
|
||||
// allocate pin & prevent other use
|
||||
if (!pinManager.allocatePin(TEMPERATURE_PIN,false))
|
||||
disabled = true;
|
||||
sensor->setWaitForConversion(false);
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Dallas Temperature not found"));
|
||||
}
|
||||
@@ -98,7 +107,7 @@ class UsermodTemperature : public Usermod {
|
||||
|
||||
void loop() {
|
||||
if (disabled || strip.isUpdating()) return;
|
||||
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
// check to see if we are due for taking a measurement
|
||||
@@ -106,21 +115,19 @@ class UsermodTemperature : public Usermod {
|
||||
// is complete the the reading is finished
|
||||
if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) return;
|
||||
|
||||
// we are due for a measurement, if we are not already waiting
|
||||
// we are due for a measurement, if we are not already waiting
|
||||
// for a conversion to complete, then make a new request for temps
|
||||
if (!waitingForConversion)
|
||||
{
|
||||
if (!waitingForConversion) {
|
||||
requestTemperatures();
|
||||
return;
|
||||
}
|
||||
|
||||
// we were waiting for a conversion to complete, have we waited log enough?
|
||||
if (now - lastTemperaturesRequest >= 94 /* 93.75ms per the datasheet */)
|
||||
{
|
||||
if (now - lastTemperaturesRequest >= 94 /* 93.75ms per the datasheet */) {
|
||||
getTemperature();
|
||||
|
||||
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
char subuf[38];
|
||||
char subuf[64];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
if (-100 <= temperature) {
|
||||
// dont publish super low temperature as the graph will get messed up
|
||||
@@ -159,11 +166,77 @@ class UsermodTemperature : public Usermod {
|
||||
}
|
||||
|
||||
temp.add(temperature);
|
||||
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||
temp.add(F("°C"));
|
||||
#else
|
||||
temp.add(F("°F"));
|
||||
#endif
|
||||
if (degC) temp.add(F("°C"));
|
||||
else temp.add(F("°F"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Add "pin_Temperature" to json state. This can be used to check which GPIO pin usermod uses.
|
||||
*/
|
||||
void addToJsonState(JsonObject &root)
|
||||
{
|
||||
root[F("pin_Temperature")] = temperaturePin;
|
||||
root[F("mode_Temperature")] = degC ? ("C") : ("F");
|
||||
}
|
||||
|
||||
/**
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
* Read "pin_Temperature" from json state and and change GPIO pin used.
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root) {
|
||||
if (root[F("pin_Temperature")] != nullptr) {
|
||||
int8_t pin = (int)root[F("pin_Temperature")];
|
||||
// deallocate pin and release memory
|
||||
pinManager.deallocatePin(temperaturePin);
|
||||
delete sensor;
|
||||
delete oneWire;
|
||||
// disable usermod
|
||||
temperaturePin = -1;
|
||||
disabled = true;
|
||||
// check if pin is OK
|
||||
if (pin>=0 && pinManager.allocatePin(pin,false)) {
|
||||
// allocat memory
|
||||
oneWire = new OneWire(pin);
|
||||
sensor = new DallasTemperature(oneWire);
|
||||
if (sensor) {
|
||||
temperaturePin = pin;
|
||||
sensor->begin();
|
||||
disabled = !sensor->getAddress(sensorDeviceAddress, 0);
|
||||
} else {
|
||||
pinManager.deallocatePin(pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (root[F("mode_Temperature")] != nullptr) {
|
||||
degC = (root[F("mode_Temperature")]==String(PSTR("C")));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
|
||||
*/
|
||||
void addToConfig(JsonObject &root) {
|
||||
// we add JSON object: {"Temperature": {"pin": 0, "degC": true}}
|
||||
JsonObject top = root.createNestedObject(F("Temperature"));
|
||||
top[F("pin")] = temperaturePin;
|
||||
top[F("degC")] = degC;
|
||||
}
|
||||
|
||||
/**
|
||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||
*/
|
||||
void readFromConfig(JsonObject &root) {
|
||||
// we look for JSON object: {"Temperature": {"pin": 0, "degC": true}}
|
||||
JsonObject top = root[F("Temperature")];
|
||||
if (!top.isNull() && top[F("pin")] != nullptr) {
|
||||
temperaturePin = (int)top[F("pin")];
|
||||
degC = top[F("degC")] != nullptr ? top[F("degC")] : true;
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("No Temperature sensor config found. (Using defaults.)"));
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
|
||||
@@ -4,7 +4,7 @@ default_envs = d1_mini
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = espressif32@3.2
|
||||
platform = espressif32@3.1.1
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
${common.build_flags_esp32}
|
||||
|
||||
109
wled00/FX.cpp
109
wled00/FX.cpp
@@ -25,7 +25,9 @@
|
||||
*/
|
||||
|
||||
#include "FX.h"
|
||||
#ifndef WLED_DISABLE_FX_HIGH_FLASH_USE
|
||||
#include "tv_colors.h"
|
||||
#endif
|
||||
|
||||
#define IBN 5100
|
||||
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
|
||||
@@ -395,41 +397,12 @@ uint16_t WS2812FX::mode_rainbow_cycle(void) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* theater chase function
|
||||
*/
|
||||
uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2, bool do_palette) {
|
||||
byte gap = 2 + ((255 - SEGMENT.intensity) >> 5);
|
||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2;
|
||||
uint32_t it = now / cycleTime;
|
||||
if (it != SEGENV.step) //new color
|
||||
{
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % gap;
|
||||
SEGENV.step = it;
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
if((i % gap) == SEGENV.aux0) {
|
||||
if (do_palette)
|
||||
{
|
||||
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else {
|
||||
setPixelColor(i, color1);
|
||||
}
|
||||
} else {
|
||||
setPixelColor(i, color2);
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Theatre-style crawling lights.
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_theater_chase(void) {
|
||||
return theater_chase(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||
return running(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -438,7 +411,7 @@ uint16_t WS2812FX::mode_theater_chase(void) {
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
|
||||
return theater_chase(color_wheel(SEGENV.step), SEGCOLOR(1), false);
|
||||
return running(color_wheel(SEGENV.step), SEGCOLOR(1), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -966,29 +939,27 @@ uint16_t WS2812FX::mode_chase_flash_random(void) {
|
||||
/*
|
||||
* Alternating pixels running function.
|
||||
*/
|
||||
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) {
|
||||
uint8_t pxw = 1 + (SEGMENT.intensity >> 5);
|
||||
uint32_t cycleTime = 35 + (255 - SEGMENT.speed);
|
||||
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2, bool theatre) {
|
||||
uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
|
||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
|
||||
uint32_t it = now / cycleTime;
|
||||
if (SEGMENT.speed == 0) it = 0;
|
||||
|
||||
bool usePalette = color1 == SEGCOLOR(0);
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
if((i + SEGENV.aux0) % (pxw*2) < pxw) {
|
||||
if (color1 == SEGCOLOR(0))
|
||||
{
|
||||
setPixelColor(SEGLEN -i -1, color_from_palette(SEGLEN -i -1, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else
|
||||
{
|
||||
setPixelColor(SEGLEN -i -1, color1);
|
||||
}
|
||||
uint32_t col = color2;
|
||||
if (usePalette) color1 = color_from_palette(i, true, PALETTE_SOLID_WRAP, 0);
|
||||
if (theatre) {
|
||||
if ((i % width) == SEGENV.aux0) col = color1;
|
||||
} else {
|
||||
setPixelColor(SEGLEN -i -1, color2);
|
||||
int8_t pos = (i % (width<<1));
|
||||
if ((pos < SEGENV.aux0-width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0+width))) col = color1;
|
||||
}
|
||||
setPixelColor(i,col);
|
||||
}
|
||||
|
||||
if (it != SEGENV.step )
|
||||
{
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % (pxw*2);
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1));
|
||||
SEGENV.step = it;
|
||||
}
|
||||
return FRAMETIME;
|
||||
@@ -1778,7 +1749,7 @@ uint16_t WS2812FX::mode_fire_2012()
|
||||
// Step 1. Cool down every cell a little
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
||||
heat[i] = (temp==0 && i<ignition) ? 2 : temp; // prevent ignition area from becoming black
|
||||
heat[i] = (temp==0 && i<ignition) ? 16 : temp; // prevent ignition area from becoming black
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
@@ -1992,7 +1963,7 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
|
||||
if (fadeUp) {
|
||||
CRGB incrementalColor = fastled_col;
|
||||
incrementalColor.nscale8_video( fadeUpAmount);
|
||||
incrementalColor.nscale8_video(fadeUpAmount);
|
||||
fastled_col += incrementalColor;
|
||||
|
||||
if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
|
||||
@@ -2000,24 +1971,21 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
}
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
|
||||
if (col_to_crgb(getPixelColor(i)) == prev) //fix "stuck" pixels
|
||||
{
|
||||
if (col_to_crgb(getPixelColor(i)) == prev) { //fix "stuck" pixels
|
||||
fastled_col += fastled_col;
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
}
|
||||
} else {
|
||||
fastled_col.nscale8( 255 - fadeDownAmount);
|
||||
fastled_col.nscale8(255 - fadeDownAmount);
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t j = 0; j <= SEGLEN / 50; j++)
|
||||
{
|
||||
for (uint16_t j = 0; j <= SEGLEN / 50; j++) {
|
||||
if (random8() <= SEGMENT.intensity) {
|
||||
for (uint8_t times = 0; times < 5; times++) //attempt to spawn a new pixel 5 times
|
||||
{
|
||||
for (uint8_t times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
|
||||
int i = random16(SEGLEN);
|
||||
if(getPixelColor(i) == 0) {
|
||||
if (getPixelColor(i) == 0) {
|
||||
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
|
||||
uint16_t index = i >> 3;
|
||||
uint8_t bitNum = i & 0x07;
|
||||
@@ -2539,7 +2507,6 @@ uint16_t WS2812FX::mode_spots_fade()
|
||||
|
||||
|
||||
//each needs 12 bytes
|
||||
//Spark type is used for popcorn and 1D fireworks
|
||||
typedef struct Ball {
|
||||
unsigned long lastBounceTime;
|
||||
float impactVelocity;
|
||||
@@ -2649,7 +2616,7 @@ uint16_t WS2812FX::mode_sinelon_dual(void) {
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::mode_sinelon_rainbow(void) {
|
||||
return sinelon_base(true, true);
|
||||
return sinelon_base(false, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -2668,7 +2635,7 @@ uint16_t WS2812FX::mode_glitter()
|
||||
|
||||
|
||||
|
||||
//each needs 12 bytes
|
||||
//each needs 11 bytes
|
||||
//Spark type is used for popcorn, 1D fireworks, and drip
|
||||
typedef struct Spark {
|
||||
float pos;
|
||||
@@ -2843,7 +2810,7 @@ typedef struct particle {
|
||||
|
||||
uint16_t WS2812FX::mode_starburst(void) {
|
||||
uint8_t numStars = 1 + (SEGLEN >> 3);
|
||||
if (numStars > 15) numStars = 15;
|
||||
if (numStars > 11) numStars = 11; // allowing for more segments
|
||||
uint16_t dataSize = sizeof(star) * numStars;
|
||||
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
@@ -2954,7 +2921,7 @@ uint16_t WS2812FX::mode_starburst(void) {
|
||||
uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
{
|
||||
//allocate segment data
|
||||
uint16_t numSparks = 2 + (SEGLEN >> 1);
|
||||
uint16_t numSparks = 2 + (SEGLEN >> 2);
|
||||
if (numSparks > 80) numSparks = 80;
|
||||
uint16_t dataSize = sizeof(spark) * numSparks;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
@@ -3050,7 +3017,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
SEGENV.aux0--;
|
||||
if (SEGENV.aux0 < 4) {
|
||||
SEGENV.aux0 = 0; //back to flare
|
||||
SEGENV.step = (SEGMENT.intensity > random8()); //decide firing side
|
||||
SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3160,8 +3127,8 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
||||
}
|
||||
|
||||
if (SEGENV.step == 0) { //init
|
||||
drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>3)+1 : random8(6,40)); // set speed
|
||||
drop->pos = SEGLEN-1; // start at end of segment
|
||||
drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>2)+1 : random8(6,64)); // set speed
|
||||
drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
|
||||
drop->col = color_from_palette(random8(0,15)<<4,false,false,0); // limit color choices so there is enough HUE gap
|
||||
SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
|
||||
SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
|
||||
@@ -3193,13 +3160,17 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
||||
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
|
||||
*/
|
||||
uint16_t WS2812FX::mode_plasma(void) {
|
||||
uint8_t thisPhase = beatsin8(6,-64,64); // Setting phase change for a couple of waves.
|
||||
uint8_t thatPhase = beatsin8(7,-64,64);
|
||||
// initialize phases on start
|
||||
if (SEGENV.call == 0) {
|
||||
SEGENV.aux0 = random8(0,2); // add a bit of randomness
|
||||
}
|
||||
uint8_t thisPhase = beatsin8(6+SEGENV.aux0,-64,64);
|
||||
uint8_t thatPhase = beatsin8(7+SEGENV.aux0,-64,64);
|
||||
|
||||
for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
|
||||
uint8_t colorIndex = cubicwave8(((i*(1+ 3*(SEGMENT.speed >> 5)))+(thisPhase)) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
|
||||
+ cos8(((i*(1+ 2*(SEGMENT.speed >> 5)))+(thatPhase)) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish.
|
||||
uint8_t thisBright = qsub8(colorIndex, beatsin8(6,0, (255 - SEGMENT.intensity)|0x01 ));
|
||||
uint8_t colorIndex = cubicwave8((i*(2+ 3*(SEGMENT.speed >> 5))+thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
|
||||
+ cos8((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish.
|
||||
uint8_t thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1))));
|
||||
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
|
||||
setPixelColor(i, color.red, color.green, color.blue);
|
||||
}
|
||||
|
||||
53
wled00/FX.h
53
wled00/FX.h
@@ -24,8 +24,6 @@
|
||||
Modified for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef WS2812FX_h
|
||||
#define WS2812FX_h
|
||||
|
||||
@@ -58,15 +56,15 @@
|
||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
#ifdef ESP8266
|
||||
#define MAX_NUM_SEGMENTS 12
|
||||
#define MAX_NUM_SEGMENTS 18
|
||||
/* How many color transitions can run at once */
|
||||
#define MAX_NUM_TRANSITIONS 8
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#define MAX_SEGMENT_DATA 2048
|
||||
#define MAX_SEGMENT_DATA 4096
|
||||
#else
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
#define MAX_NUM_TRANSITIONS 16
|
||||
#define MAX_SEGMENT_DATA 8192
|
||||
#define MAX_NUM_SEGMENTS 24
|
||||
#define MAX_NUM_TRANSITIONS 24
|
||||
#define MAX_SEGMENT_DATA 20480
|
||||
#endif
|
||||
|
||||
#define LED_SKIP_AMOUNT 1
|
||||
@@ -78,7 +76,7 @@
|
||||
#define SEGENV _segment_runtimes[_segment_index]
|
||||
#define SEGLEN _virtualSegmentLength
|
||||
#define SEGACT SEGMENT.stop
|
||||
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGLEN
|
||||
#define SPEED_FORMULA_L (uint16_t)(5 + (50*(255 - SEGMENT.speed))/SEGLEN)
|
||||
#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes))
|
||||
|
||||
// some common colors
|
||||
@@ -296,19 +294,19 @@ class WS2812FX {
|
||||
{
|
||||
return ((options >> n) & 0x01);
|
||||
}
|
||||
bool isSelected()
|
||||
inline bool isSelected()
|
||||
{
|
||||
return getOption(0);
|
||||
}
|
||||
bool isActive()
|
||||
inline bool isActive()
|
||||
{
|
||||
return stop > start;
|
||||
}
|
||||
uint16_t length()
|
||||
inline uint16_t length()
|
||||
{
|
||||
return stop - start;
|
||||
}
|
||||
uint16_t groupLength()
|
||||
inline uint16_t groupLength()
|
||||
{
|
||||
return grouping + spacing;
|
||||
}
|
||||
@@ -324,11 +322,11 @@ class WS2812FX {
|
||||
|
||||
// segment runtime parameters
|
||||
typedef struct Segment_runtime { // 28 bytes
|
||||
unsigned long next_time;
|
||||
uint32_t step;
|
||||
uint32_t call;
|
||||
uint16_t aux0;
|
||||
uint16_t aux1;
|
||||
unsigned long next_time; // millis() of next update
|
||||
uint32_t step; // custom "step" var
|
||||
uint32_t call; // call counter
|
||||
uint16_t aux0; // custom var
|
||||
uint16_t aux1; // custom var
|
||||
byte* data = nullptr;
|
||||
bool allocateData(uint16_t len){
|
||||
if (data && _dataLen == len) return true; //already allocated
|
||||
@@ -368,7 +366,7 @@ class WS2812FX {
|
||||
* the internal segment state should be reset.
|
||||
* Call resetIfRequired before calling the next effect function.
|
||||
*/
|
||||
void reset() { _requiresReset = true; }
|
||||
inline void reset() { _requiresReset = true; }
|
||||
private:
|
||||
uint16_t _dataLen = 0;
|
||||
bool _requiresReset = false;
|
||||
@@ -584,7 +582,7 @@ class WS2812FX {
|
||||
}
|
||||
|
||||
void
|
||||
finalizeInit(uint16_t countPixels, bool skipFirst),
|
||||
finalizeInit(void),
|
||||
service(void),
|
||||
blur(uint8_t),
|
||||
fill(uint32_t),
|
||||
@@ -601,10 +599,10 @@ class WS2812FX {
|
||||
trigger(void),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
|
||||
resetSegments(),
|
||||
populateDefaultSegments(),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
show(void),
|
||||
setColorOrder(uint8_t co),
|
||||
setPixelSegment(uint8_t n);
|
||||
|
||||
bool
|
||||
@@ -623,8 +621,6 @@ class WS2812FX {
|
||||
paletteFade = 0,
|
||||
paletteBlend = 0,
|
||||
milliampsPerLed = 55,
|
||||
// getStripType(uint8_t strip=0),
|
||||
// setStripType(uint8_t type, uint8_t strip=0),
|
||||
getBrightness(void),
|
||||
getMode(void),
|
||||
getSpeed(void),
|
||||
@@ -633,23 +629,16 @@ class WS2812FX {
|
||||
getMaxSegments(void),
|
||||
//getFirstSelectedSegment(void),
|
||||
getMainSegmentId(void),
|
||||
getColorOrder(void),
|
||||
gamma8(uint8_t),
|
||||
gamma8_cal(uint8_t, float),
|
||||
get_random_wheel_index(uint8_t);
|
||||
|
||||
int8_t
|
||||
// setStripPin(uint8_t strip, int8_t pin),
|
||||
// getStripPin(uint8_t strip=0),
|
||||
// setStripPinClk(uint8_t strip, int8_t pin),
|
||||
// getStripPinClk(uint8_t strip=0),
|
||||
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
|
||||
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
// setStripLen(uint8_t strip, uint16_t len),
|
||||
// getStripLen(uint8_t strip=0),
|
||||
triwave16(uint16_t),
|
||||
getFps();
|
||||
|
||||
@@ -802,7 +791,7 @@ class WS2812FX {
|
||||
CRGBPalette16 currentPalette;
|
||||
CRGBPalette16 targetPalette;
|
||||
|
||||
uint16_t _length, _lengthRaw, _virtualSegmentLength;
|
||||
uint16_t _length, _virtualSegmentLength;
|
||||
uint16_t _rand16seed;
|
||||
uint8_t _brightness;
|
||||
uint16_t _usedSegmentData = 0;
|
||||
@@ -814,7 +803,6 @@ class WS2812FX {
|
||||
void handle_palette(void);
|
||||
|
||||
bool
|
||||
_skipFirstMode,
|
||||
_triggered;
|
||||
|
||||
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
|
||||
@@ -828,7 +816,6 @@ class WS2812FX {
|
||||
color_wipe(bool, bool),
|
||||
dynamic(bool),
|
||||
scan(bool),
|
||||
theater_chase(uint32_t, uint32_t, bool),
|
||||
running_base(bool),
|
||||
larson_scanner(bool),
|
||||
sinelon_base(bool,bool),
|
||||
@@ -837,7 +824,7 @@ class WS2812FX {
|
||||
gradient_base(bool),
|
||||
ripple_base(bool),
|
||||
police_base(uint32_t, uint32_t, bool),
|
||||
running(uint32_t, uint32_t),
|
||||
running(uint32_t, uint32_t, bool theatre=false),
|
||||
tricolor_chase(uint32_t, uint32_t),
|
||||
twinklefox_base(bool),
|
||||
spots_base(uint16_t),
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
Modified heavily for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
#include "FX.h"
|
||||
#include "palettes.h"
|
||||
|
||||
@@ -40,33 +40,52 @@
|
||||
another example. Switches direction every 5 LEDs.
|
||||
{"map":[
|
||||
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]}
|
||||
*/
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void WS2812FX::finalizeInit(uint16_t countPixels, bool skipFirst)
|
||||
void WS2812FX::finalizeInit(void)
|
||||
{
|
||||
RESET_RUNTIME;
|
||||
_length = countPixels;
|
||||
_skipFirstMode = skipFirst;
|
||||
isRgbw = false;
|
||||
|
||||
_lengthRaw = _length;
|
||||
if (_skipFirstMode) {
|
||||
_lengthRaw += LED_SKIP_AMOUNT;
|
||||
}
|
||||
|
||||
//if busses failed to load, add default (FS issue...)
|
||||
//if busses failed to load, add default (fresh install, FS issue, ...)
|
||||
if (busses.getNumBusses() == 0) {
|
||||
uint8_t defPin[] = {LEDPIN};
|
||||
BusConfig defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, _lengthRaw, COL_ORDER_GRB);
|
||||
BusConfig defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, 30, COL_ORDER_GRB, false, false);
|
||||
busses.add(defCfg);
|
||||
#ifdef LEDPIN1
|
||||
defPin[0] = {LEDPIN1};
|
||||
defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, 30, COL_ORDER_GRB, false, false);
|
||||
busses.add(defCfg);
|
||||
#endif
|
||||
#ifdef LEDPIN2
|
||||
defPin[0] = {LEDPIN2};
|
||||
defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, 30, COL_ORDER_GRB, false, false);
|
||||
busses.add(defCfg);
|
||||
#endif
|
||||
#ifdef LEDPIN3
|
||||
defPin[0] = {LEDPIN3};
|
||||
defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, 30, COL_ORDER_GRB, false, false);
|
||||
busses.add(defCfg);
|
||||
#endif
|
||||
}
|
||||
|
||||
deserializeMap();
|
||||
|
||||
_length = 0;
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
if (_length+bus->getLength() > MAX_LEDS) break;
|
||||
isRgbw |= bus->isRgbw();
|
||||
_length += bus->getLength();
|
||||
}
|
||||
/*
|
||||
//make segment 0 cover the entire strip
|
||||
_segments[0].start = 0;
|
||||
_segments[0].stop = _length;
|
||||
*/
|
||||
|
||||
setBrightness(_brightness);
|
||||
|
||||
@@ -147,14 +166,13 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
int16_t realIndex = iGroup;
|
||||
if (IS_REVERSE) {
|
||||
if (IS_MIRROR) {
|
||||
realIndex = (SEGMENT.length() -1) / 2 - iGroup; //only need to index half the pixels
|
||||
realIndex = (SEGMENT.length() - 1) / 2 - iGroup; //only need to index half the pixels
|
||||
} else {
|
||||
realIndex = SEGMENT.length() - iGroup - 1;
|
||||
realIndex = (SEGMENT.length() - 1) - iGroup;
|
||||
}
|
||||
}
|
||||
|
||||
realIndex += SEGMENT.start;
|
||||
|
||||
return realIndex;
|
||||
}
|
||||
|
||||
@@ -174,9 +192,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
|
||||
if (SEGLEN) {//from segment
|
||||
|
||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||
if (_bri_t < 255) {
|
||||
r = scale8(r, _bri_t);
|
||||
@@ -186,32 +202,25 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
|
||||
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */
|
||||
bool reversed = IS_REVERSE;
|
||||
/* Set all the pixels in the group */
|
||||
uint16_t realIndex = realPixelIndex(i);
|
||||
|
||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||
int16_t indexSet = realIndex + (reversed ? -j : j);
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
||||
busses.setPixelColor(indexSet + skip, col);
|
||||
int16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
|
||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) { // watch for group out of bounds condition
|
||||
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
||||
uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1;
|
||||
if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir];
|
||||
busses.setPixelColor(indexMir + skip, col);
|
||||
int16_t indexSetRev = SEGMENT.stop + SEGMENT.start - indexSet - 1;
|
||||
if (indexSetRev < customMappingSize) indexSetRev = customMappingTable[indexSetRev];
|
||||
busses.setPixelColor(indexSetRev, col);
|
||||
}
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
busses.setPixelColor(indexSet, col);
|
||||
}
|
||||
}
|
||||
} else { //live data, etc.
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
busses.setPixelColor(i + skip, col);
|
||||
}
|
||||
if (skip && i == 0) {
|
||||
for (uint16_t j = 0; j < skip; j++) {
|
||||
busses.setPixelColor(j, BLACK);
|
||||
}
|
||||
busses.setPixelColor(i, col);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,11 +493,9 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
i = realPixelIndex(i);
|
||||
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
|
||||
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
|
||||
|
||||
if (i >= _lengthRaw) return 0;
|
||||
if (i >= _length) return 0;
|
||||
|
||||
// TODO: may need to add IS_REVERSE and IS_MIRROR logic
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
@@ -509,14 +516,14 @@ uint32_t WS2812FX::getLastShow(void) {
|
||||
return _lastShow;
|
||||
}
|
||||
|
||||
//TODO these need to be on a per-strip basis
|
||||
uint8_t WS2812FX::getColorOrder(void) {
|
||||
return COL_ORDER_GRB;
|
||||
}
|
||||
|
||||
void WS2812FX::setColorOrder(uint8_t co) {
|
||||
//bus->SetColorOrder(co);
|
||||
}
|
||||
// there is no longer any need for these two
|
||||
//uint8_t WS2812FX::getColorOrder(void) {
|
||||
// return COL_ORDER_GRB;
|
||||
//}
|
||||
//
|
||||
//void WS2812FX::setColorOrder(uint8_t co) {
|
||||
// //bus->SetColorOrder(co);
|
||||
//}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
|
||||
if (n >= MAX_NUM_SEGMENTS) return;
|
||||
@@ -581,6 +588,25 @@ void WS2812FX::resetSegments() {
|
||||
_segment_runtimes[0].reset();
|
||||
}
|
||||
|
||||
void WS2812FX::populateDefaultSegments() {
|
||||
uint16_t length = 0;
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
_segments[i].start = bus->getStart();
|
||||
length += bus->getLength();
|
||||
_segments[i].stop = _segments[i].start + bus->getLength();
|
||||
_segments[i].mode = DEFAULT_MODE;
|
||||
_segments[i].colors[0] = DEFAULT_COLOR;
|
||||
_segments[i].speed = DEFAULT_SPEED;
|
||||
_segments[i].intensity = DEFAULT_INTENSITY;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].setOption(SEG_OPTION_SELECTED, 1);
|
||||
_segments[i].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[i].opacity = 255;
|
||||
}
|
||||
}
|
||||
|
||||
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
|
||||
void WS2812FX::setPixelSegment(uint8_t n)
|
||||
{
|
||||
|
||||
@@ -10,16 +10,24 @@
|
||||
#include "bus_wrapper.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define GET_BIT(var,bit) (((var)>>(bit))&0x01)
|
||||
#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
|
||||
#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
|
||||
|
||||
//temporary struct for passing bus configuration to bus
|
||||
struct BusConfig {
|
||||
uint8_t type = TYPE_WS2812_RGB;
|
||||
uint16_t count = 1;
|
||||
uint16_t start = 0;
|
||||
uint8_t colorOrder = COL_ORDER_GRB;
|
||||
bool reversed = false;
|
||||
uint16_t count;
|
||||
uint16_t start;
|
||||
uint8_t colorOrder;
|
||||
bool reversed;
|
||||
uint8_t skipAmount;
|
||||
bool rgbwOverride;
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false) {
|
||||
type = busType; count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev;
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0) {
|
||||
rgbwOverride = (bool) GET_BIT(busType,7);
|
||||
type = busType & 0x7F; // bit 7 is hacked to include RGBW info (1=RGBW, 0=RGB)
|
||||
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
|
||||
uint8_t nPins = 1;
|
||||
if (type > 47) nPins = 2;
|
||||
else if (type > 41 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||
@@ -51,7 +59,7 @@ class Bus {
|
||||
|
||||
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
|
||||
|
||||
uint16_t getStart() {
|
||||
inline uint16_t getStart() {
|
||||
return _start;
|
||||
}
|
||||
|
||||
@@ -60,7 +68,7 @@ class Bus {
|
||||
}
|
||||
|
||||
virtual uint16_t getLength() {
|
||||
return 1;
|
||||
return 1; // is this ok? shouldn't it be 0 in virtual function?
|
||||
}
|
||||
|
||||
virtual void setColorOrder() {}
|
||||
@@ -69,11 +77,19 @@ class Bus {
|
||||
return COL_ORDER_RGB;
|
||||
}
|
||||
|
||||
uint8_t getType() {
|
||||
virtual bool isRgbw() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual uint8_t skipFirstLed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline uint8_t getType() {
|
||||
return _type;
|
||||
}
|
||||
|
||||
bool isOk() {
|
||||
inline bool isOk() {
|
||||
return _valid;
|
||||
}
|
||||
|
||||
@@ -90,30 +106,32 @@ class Bus {
|
||||
class BusDigital : public Bus {
|
||||
public:
|
||||
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) {
|
||||
if (!IS_DIGITAL(bc.type) || !bc.count) return;
|
||||
uint8_t type = bc.type;
|
||||
if (!IS_DIGITAL(type) || !bc.count) return;
|
||||
_pins[0] = bc.pins[0];
|
||||
if (!pinManager.allocatePin(_pins[0])) return;
|
||||
if (IS_2PIN(bc.type)) {
|
||||
if (IS_2PIN(type)) {
|
||||
_pins[1] = bc.pins[1];
|
||||
if (!pinManager.allocatePin(_pins[1])) {
|
||||
cleanup(); return;
|
||||
}
|
||||
}
|
||||
_len = bc.count;
|
||||
reversed = bc.reversed;
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
_skip = bc.skipAmount; //sacrificial pixels
|
||||
_len = bc.count + _skip;
|
||||
_rgbw = bc.rgbwOverride; // RGBW override in bit 7
|
||||
_iType = PolyBus::getI(type, _pins, nr, _rgbw);
|
||||
if (_iType == I_NONE) return;
|
||||
_busPtr = PolyBus::create(_iType, _pins, _len);
|
||||
_valid = (_busPtr != nullptr);
|
||||
_colorOrder = bc.colorOrder;
|
||||
//Serial.printf("Successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n",nr, len, type, pins[0],pins[1],_iType);
|
||||
};
|
||||
|
||||
void show() {
|
||||
inline void show() {
|
||||
PolyBus::show(_busPtr, _iType);
|
||||
}
|
||||
|
||||
bool canShow() {
|
||||
inline bool canShow() {
|
||||
return PolyBus::canShow(_busPtr, _iType);
|
||||
}
|
||||
|
||||
@@ -130,20 +148,22 @@ class BusDigital : public Bus {
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
else pix += _skip;
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder);
|
||||
}
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
else pix += _skip;
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder);
|
||||
}
|
||||
|
||||
uint8_t getColorOrder() {
|
||||
inline uint8_t getColorOrder() {
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
uint16_t getLength() {
|
||||
return _len;
|
||||
inline uint16_t getLength() {
|
||||
return _len - _skip;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray) {
|
||||
@@ -157,12 +177,19 @@ class BusDigital : public Bus {
|
||||
_colorOrder = colorOrder;
|
||||
}
|
||||
|
||||
void reinit() {
|
||||
inline bool isRgbw() {
|
||||
return _rgbw;
|
||||
}
|
||||
|
||||
inline uint8_t skipFirstLed() {
|
||||
return _skip;
|
||||
}
|
||||
|
||||
inline void reinit() {
|
||||
PolyBus::begin(_busPtr, _iType, _pins);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
//Serial.println("Digital Cleanup");
|
||||
PolyBus::cleanup(_busPtr, _iType);
|
||||
_iType = I_NONE;
|
||||
_valid = false;
|
||||
@@ -180,6 +207,8 @@ class BusDigital : public Bus {
|
||||
uint8_t _pins[2] = {255, 255};
|
||||
uint8_t _iType = I_NONE;
|
||||
uint16_t _len = 0;
|
||||
uint8_t _skip = 0;
|
||||
bool _rgbw = false;
|
||||
void * _busPtr = nullptr;
|
||||
};
|
||||
|
||||
@@ -190,6 +219,11 @@ class BusPwm : public Bus {
|
||||
if (!IS_PWM(bc.type)) return;
|
||||
uint8_t numPins = NUM_PWM_PINS(bc.type);
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
Serial.print(F("Init: Number of pins="));
|
||||
Serial.println(numPins);
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
analogWriteRange(255); //same range as one RGB channel
|
||||
analogWriteFreq(WLED_PWM_FREQ);
|
||||
@@ -203,7 +237,8 @@ class BusPwm : public Bus {
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
_pins[i] = bc.pins[i];
|
||||
if (!pinManager.allocatePin(_pins[i])) {
|
||||
deallocatePins(); return;
|
||||
//deallocatePins(); return;
|
||||
_pins[i] = 255; break;
|
||||
}
|
||||
#ifdef ESP8266
|
||||
pinMode(_pins[i], OUTPUT);
|
||||
@@ -255,17 +290,23 @@ class BusPwm : public Bus {
|
||||
}
|
||||
}
|
||||
|
||||
void setBrightness(uint8_t b) {
|
||||
inline void setBrightness(uint8_t b) {
|
||||
_bri = b;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray) {
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
pinArray[i] = _pins[i];
|
||||
}
|
||||
return numPins;
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
bool isRgbw() {
|
||||
return (_type > TYPE_ONOFF && _type <= TYPE_ANALOG_5CH && _type != TYPE_ANALOG_3CH);
|
||||
}
|
||||
|
||||
inline void cleanup() {
|
||||
deallocatePins();
|
||||
}
|
||||
|
||||
@@ -283,13 +324,13 @@ class BusPwm : public Bus {
|
||||
void deallocatePins() {
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
pinManager.deallocatePin(_pins[i]);
|
||||
if (!pinManager.isPinOk(_pins[i])) continue;
|
||||
#ifdef ESP8266
|
||||
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
|
||||
#else
|
||||
if (_ledcStart < 16) ledcDetachPin(_pins[i]);
|
||||
#endif
|
||||
pinManager.deallocatePin(_pins[i]);
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
pinManager.deallocateLedc(_ledcStart, numPins);
|
||||
@@ -304,7 +345,7 @@ class BusManager {
|
||||
};
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
uint32_t memUsage(BusConfig &bc) {
|
||||
static uint32_t memUsage(BusConfig &bc) {
|
||||
uint8_t type = bc.type;
|
||||
uint16_t len = bc.count;
|
||||
if (type < 32) {
|
||||
@@ -333,8 +374,7 @@ class BusManager {
|
||||
} else {
|
||||
busses[numBusses] = new BusPwm(bc);
|
||||
}
|
||||
numBusses++;
|
||||
return numBusses -1;
|
||||
return numBusses++;
|
||||
}
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
@@ -358,6 +398,7 @@ class BusManager {
|
||||
uint16_t bstart = b->getStart();
|
||||
if (pix < bstart || pix >= bstart + b->getLength()) continue;
|
||||
busses[i]->setPixelColor(pix - bstart, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,10 +430,16 @@ class BusManager {
|
||||
return busses[busNr];
|
||||
}
|
||||
|
||||
uint8_t getNumBusses() {
|
||||
inline uint8_t getNumBusses() {
|
||||
return numBusses;
|
||||
}
|
||||
|
||||
uint16_t getTotalLength() {
|
||||
uint16_t len = 0;
|
||||
for (uint8_t i=0; i<numBusses; i++ ) len += busses[i]->getLength();
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool isRgbw(uint8_t type) {
|
||||
if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true;
|
||||
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true;
|
||||
|
||||
@@ -79,23 +79,25 @@
|
||||
#define I_32_R7_TM1_4 54
|
||||
#define I_32_I0_TM1_4 55
|
||||
#define I_32_I1_TM1_4 56
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//Bit Bang theoretically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
|
||||
//APA102
|
||||
#define I_HS_DOT_3 57 //hardware SPI
|
||||
#define I_SS_DOT_3 58 //soft SPI
|
||||
#define I_HS_DOT_4 59 //hardware SPI, RGBW?
|
||||
#define I_SS_DOT_4 60 //soft SPI, RGBW?
|
||||
|
||||
//LPD8806
|
||||
#define I_HS_LPD_3 59
|
||||
#define I_SS_LPD_3 60
|
||||
#define I_HS_LPD_3 61
|
||||
#define I_SS_LPD_3 62
|
||||
|
||||
//WS2801
|
||||
#define I_HS_WS1_3 61
|
||||
#define I_SS_WS1_3 62
|
||||
#define I_HS_WS1_3 63
|
||||
#define I_SS_WS1_3 64
|
||||
|
||||
//P9813
|
||||
#define I_HS_P98_3 63
|
||||
#define I_SS_P98_3 64
|
||||
#define I_HS_P98_3 65
|
||||
#define I_SS_P98_3 66
|
||||
|
||||
|
||||
/*** ESP8266 Neopixel methods ***/
|
||||
@@ -173,15 +175,20 @@
|
||||
#endif
|
||||
|
||||
//APA102
|
||||
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> //hardware SPI
|
||||
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> //soft SPI
|
||||
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> // hardware SPI
|
||||
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> // soft SPI
|
||||
#define B_HS_DOT_4 NeoPixelBrightnessBus<DotStarLbgrFeature,DotStarSpiMethod> // HW SPI, RGBW mode?
|
||||
#define B_SS_DOT_4 NeoPixelBrightnessBus<DotStarLbgrFeature,DotStarMethod> // soft SPI, RGBW mode?
|
||||
|
||||
//LPD8806
|
||||
#define B_HS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806SpiMethod>
|
||||
#define B_SS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806Method>
|
||||
|
||||
//WS2801
|
||||
#define B_HS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801SpiMethod>
|
||||
//#define B_HS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801Spi40MhzMethod>
|
||||
//#define B_HS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801Spi20MhzMethod>
|
||||
//#define B_HS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801SpiMethod> // 10MHz
|
||||
#define B_HS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801Spi2MhzMethod> //slower, more compatible
|
||||
#define B_SS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801Method>
|
||||
|
||||
//P9813
|
||||
@@ -212,6 +219,7 @@ class PolyBus {
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->Begin(); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(); break;
|
||||
@@ -259,11 +267,13 @@ class PolyBus {
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Begin(); break;
|
||||
// ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin()
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
#endif
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->Begin(); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break;
|
||||
@@ -336,6 +346,8 @@ class PolyBus {
|
||||
// for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat)
|
||||
case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break;
|
||||
case I_SS_DOT_3: busPtr = new B_SS_DOT_3(len, pins[1], pins[0]); break;
|
||||
case I_HS_DOT_4: busPtr = new B_HS_DOT_4(len, pins[1], pins[0]); break;
|
||||
case I_SS_DOT_4: busPtr = new B_SS_DOT_4(len, pins[1], pins[0]); break;
|
||||
case I_HS_LPD_3: busPtr = new B_HS_LPD_3(len, pins[1], pins[0]); break;
|
||||
case I_SS_LPD_3: busPtr = new B_SS_LPD_3(len, pins[1], pins[0]); break;
|
||||
case I_HS_WS1_3: busPtr = new B_HS_WS1_3(len, pins[1], pins[0]); break;
|
||||
@@ -411,6 +423,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->Show(); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->Show(); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(); break;
|
||||
@@ -484,6 +498,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: return (static_cast<B_HS_DOT_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_DOT_3: return (static_cast<B_SS_DOT_3*>(busPtr))->CanShow(); break;
|
||||
case I_HS_DOT_4: return (static_cast<B_HS_DOT_4*>(busPtr))->CanShow(); break;
|
||||
case I_SS_DOT_4: return (static_cast<B_SS_DOT_4*>(busPtr))->CanShow(); break;
|
||||
case I_HS_LPD_3: return (static_cast<B_HS_LPD_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_LPD_3: return (static_cast<B_SS_LPD_3*>(busPtr))->CanShow(); break;
|
||||
case I_HS_WS1_3: return (static_cast<B_HS_WS1_3*>(busPtr))->CanShow(); break;
|
||||
@@ -500,11 +516,6 @@ class PolyBus {
|
||||
uint8_t w = c >> 24;
|
||||
RgbwColor col;
|
||||
|
||||
//TODO make color order override possible on a per-strip basis
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (pix >= COO_MIN && pix < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
//reorder channels to selected order
|
||||
switch (co)
|
||||
{
|
||||
@@ -581,6 +592,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
@@ -654,6 +667,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetBrightness(b); break;
|
||||
@@ -728,6 +743,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: col = (static_cast<B_HS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_DOT_3: col = (static_cast<B_SS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_DOT_4: col = (static_cast<B_HS_DOT_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_DOT_4: col = (static_cast<B_SS_DOT_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_LPD_3: col = (static_cast<B_HS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_LPD_3: col = (static_cast<B_SS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_WS1_3: col = (static_cast<B_HS_WS1_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
@@ -736,10 +753,6 @@ class PolyBus {
|
||||
case I_SS_P98_3: col = (static_cast<B_SS_P98_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
}
|
||||
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (pix >= COO_MIN && pix < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
switch (co)
|
||||
{
|
||||
// W G R B
|
||||
@@ -819,6 +832,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: delete (static_cast<B_HS_DOT_3*>(busPtr)); break;
|
||||
case I_SS_DOT_3: delete (static_cast<B_SS_DOT_3*>(busPtr)); break;
|
||||
case I_HS_DOT_4: delete (static_cast<B_HS_DOT_4*>(busPtr)); break;
|
||||
case I_SS_DOT_4: delete (static_cast<B_SS_DOT_4*>(busPtr)); break;
|
||||
case I_HS_LPD_3: delete (static_cast<B_HS_LPD_3*>(busPtr)); break;
|
||||
case I_SS_LPD_3: delete (static_cast<B_SS_LPD_3*>(busPtr)); break;
|
||||
case I_HS_WS1_3: delete (static_cast<B_HS_WS1_3*>(busPtr)); break;
|
||||
@@ -829,18 +844,21 @@ class PolyBus {
|
||||
}
|
||||
|
||||
//gives back the internal type index (I_XX_XXX_X above) for the input
|
||||
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) {
|
||||
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0, bool rgbwOverride = false) {
|
||||
if (!IS_DIGITAL(busType)) return I_NONE;
|
||||
if (IS_2PIN(busType)) { //SPI LED chips
|
||||
bool isHSPI = false;
|
||||
#ifdef ESP8266
|
||||
if (pins[0] == P_8266_HS_MOSI && pins[1] == P_8266_HS_CLK) isHSPI = true;
|
||||
#else
|
||||
if(!num) isHSPI = true; // temporary hack to limit use of hardware SPI to a single SPI peripheral: only allow ESP32 hardware serial on segment 0
|
||||
// temporary hack to limit use of hardware SPI to a single SPI peripheral: only allow ESP32 hardware serial on segment 0
|
||||
if (!num) isHSPI = true;
|
||||
//if (num==0 && pins[0] == P_32_VS_MOSI && pins[1] == P_32_VS_CLK) isHSPI = true; // no nultiplexing, up to 80MHz clock
|
||||
//if (num==1 && pins[0] == P_32_HS_MOSI && pins[1] == P_32_HS_CLK) isHSPI = true;
|
||||
#endif
|
||||
uint8_t t = I_NONE;
|
||||
switch (busType) {
|
||||
case TYPE_APA102: t = I_SS_DOT_3; break;
|
||||
case TYPE_APA102: t = rgbwOverride ? I_SS_DOT_4 : I_SS_DOT_3; break;
|
||||
case TYPE_LPD8806: t = I_SS_LPD_3; break;
|
||||
case TYPE_WS2801: t = I_SS_WS1_3; break;
|
||||
case TYPE_P9813: t = I_SS_P98_3; break;
|
||||
@@ -855,9 +873,9 @@ class PolyBus {
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_RGB:
|
||||
case TYPE_WS2812_WWA:
|
||||
return I_8266_U0_NEO_3 + offset;
|
||||
// return I_8266_U0_NEO_3 + offset;
|
||||
case TYPE_SK6812_RGBW:
|
||||
return I_8266_U0_NEO_4 + offset;
|
||||
return (rgbwOverride ? I_8266_U0_NEO_4 : I_8266_U0_NEO_3) + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_8266_U0_400_3 + offset;
|
||||
}
|
||||
@@ -867,9 +885,9 @@ class PolyBus {
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_RGB:
|
||||
case TYPE_WS2812_WWA:
|
||||
return I_32_R0_NEO_3 + offset;
|
||||
// return I_32_R0_NEO_3 + offset;
|
||||
case TYPE_SK6812_RGBW:
|
||||
return I_32_R0_NEO_4 + offset;
|
||||
return (rgbwOverride ? I_32_R0_NEO_4 : I_32_R0_NEO_3) + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_32_R0_400_3 + offset;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,8 @@ void handleIO()
|
||||
{
|
||||
if (!offMode) {
|
||||
#ifdef ESP8266
|
||||
//turn off built-in LED if strip is turned off
|
||||
// turn off built-in LED if strip is turned off
|
||||
// this will break digital bus so will need to be reinitialised on On
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
@@ -105,31 +106,4 @@ void handleIO()
|
||||
}
|
||||
offMode = true;
|
||||
}
|
||||
|
||||
//output
|
||||
if (auxPin>=1 && (auxActive || auxActiveBefore))
|
||||
{
|
||||
if (!auxActiveBefore)
|
||||
{
|
||||
auxActiveBefore = true;
|
||||
switch (auxTriggeredState)
|
||||
{
|
||||
case 0: pinMode(auxPin, INPUT); break;
|
||||
case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
|
||||
case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
|
||||
}
|
||||
auxStartTime = millis();
|
||||
}
|
||||
if ((millis() - auxStartTime > auxTime*1000 && auxTime != 255) || !auxActive)
|
||||
{
|
||||
auxActive = false;
|
||||
auxActiveBefore = false;
|
||||
switch (auxDefaultState)
|
||||
{
|
||||
case 0: pinMode(auxPin, INPUT); break;
|
||||
case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
|
||||
case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,8 @@ void deserializeConfig() {
|
||||
JsonArray ap_ip = ap["ip"];
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
apIP[i] = ap_ip;
|
||||
}*/
|
||||
}
|
||||
*/
|
||||
|
||||
noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted
|
||||
noWifiSleep = !noWifiSleep;
|
||||
@@ -92,54 +93,56 @@ void deserializeConfig() {
|
||||
|
||||
CJSON(ledCount, hw_led[F("total")]);
|
||||
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
||||
uint16_t lC = 0;
|
||||
|
||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
||||
//CJSON(strip.reverseMode, hw_led["rev"]);
|
||||
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
uint8_t s = 0; //bus iterator
|
||||
uint8_t s = 0; // bus iterator
|
||||
strip.isRgbw = false;
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES) break;
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
JsonArray pinArr = elm[F("pin")];
|
||||
JsonArray pinArr = elm["pin"];
|
||||
if (pinArr.size() == 0) continue;
|
||||
pins[0] = pinArr[0];
|
||||
uint8_t i = 0;
|
||||
for (int p : pinArr) {
|
||||
pins[i] = p;
|
||||
i++;
|
||||
pins[i++] = p;
|
||||
if (i>4) break;
|
||||
}
|
||||
|
||||
uint16_t length = elm[F("len")];
|
||||
if (length==0) continue;
|
||||
uint8_t colorOrder = (int)elm[F("order")];
|
||||
//only use skip from the first strip (this shouldn't have been in ins obj. but remains here for compatibility)
|
||||
if (s==0) skipFirstLed = elm[F("skip")];
|
||||
if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
|
||||
uint16_t start = elm[F("start")] | 0;
|
||||
if (start >= ledCount) continue;
|
||||
if (start >= lC+length) continue; // something is very wrong :)
|
||||
//limit length of strip if it would exceed total configured LEDs
|
||||
if (start + length > ledCount) length = ledCount - start;
|
||||
//if (start + length > ledCount) length = ledCount - start;
|
||||
uint8_t colorOrder = elm[F("order")];
|
||||
uint8_t skipFirst = elm[F("skip")];
|
||||
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
|
||||
bool reversed = elm["rev"];
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(ledType));
|
||||
if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary)
|
||||
strip.isRgbw |= (bool)elm[F("rgbw")]; //(strip.isRgbw || BusManager::isRgbw(ledType));
|
||||
s++;
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed);
|
||||
mem += busses.memUsage(bc);
|
||||
lC += length;
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||
mem += BusManager::memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY) busses.add(bc);
|
||||
}
|
||||
strip.finalizeInit(ledCount, skipFirstLed);
|
||||
if (lC > ledCount) ledCount = lC; // fix incorrect total length (honour analog setup)
|
||||
//strip.finalizeInit(); // will be done in WLED::beginStrip()
|
||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||
|
||||
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
|
||||
CJSON(buttonEnabled, hw_btn_ins_0["type"]);
|
||||
int hw_btn_pin = hw_btn_ins_0[F("pin")][0];
|
||||
if (pinManager.allocatePin(hw_btn_pin,false)) {
|
||||
int hw_btn_pin = hw_btn_ins_0["pin"][0];
|
||||
if (hw_btn_pin>=0 && pinManager.allocatePin(hw_btn_pin,false)) {
|
||||
btnPin = hw_btn_pin;
|
||||
pinMode(btnPin, INPUT_PULLUP);
|
||||
} else {
|
||||
@@ -155,7 +158,7 @@ void deserializeConfig() {
|
||||
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
int hw_ir_pin = hw["ir"]["pin"] | -1; // 4
|
||||
if (pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
if (hw_ir_pin >=0 && pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
irPin = hw_ir_pin;
|
||||
} else {
|
||||
irPin = -1;
|
||||
@@ -164,9 +167,8 @@ void deserializeConfig() {
|
||||
CJSON(irEnabled, hw["ir"]["type"]);
|
||||
|
||||
JsonObject relay = hw[F("relay")];
|
||||
|
||||
int hw_relay_pin = relay["pin"];
|
||||
if (pinManager.allocatePin(hw_relay_pin,true)) {
|
||||
int hw_relay_pin = relay["pin"] | -1;
|
||||
if (hw_relay_pin>=0 && pinManager.allocatePin(hw_relay_pin,true)) {
|
||||
rlyPin = hw_relay_pin;
|
||||
pinMode(rlyPin, OUTPUT);
|
||||
} else {
|
||||
@@ -176,7 +178,7 @@ void deserializeConfig() {
|
||||
rlyMde = !relay["rev"];
|
||||
}
|
||||
|
||||
//int hw_status_pin = hw[F("status")][F("pin")]; // -1
|
||||
//int hw_status_pin = hw[F("status")]["pin"]; // -1
|
||||
|
||||
JsonObject light = doc[F("light")];
|
||||
CJSON(briMultiplier, light[F("scale-bri")]);
|
||||
@@ -306,6 +308,8 @@ void deserializeConfig() {
|
||||
CJSON(currentTimezone, if_ntp[F("tz")]);
|
||||
CJSON(utcOffsetSecs, if_ntp[F("offset")]);
|
||||
CJSON(useAMPM, if_ntp[F("ampm")]);
|
||||
CJSON(longitude, if_ntp[F("ln")]);
|
||||
CJSON(latitude, if_ntp[F("lt")]);
|
||||
|
||||
JsonObject ol = doc[F("ol")];
|
||||
CJSON(overlayDefault ,ol[F("clock")]); // 0
|
||||
@@ -334,7 +338,8 @@ void deserializeConfig() {
|
||||
JsonArray timers = tm[F("ins")];
|
||||
uint8_t it = 0;
|
||||
for (JsonObject timer : timers) {
|
||||
if (it > 7) break;
|
||||
if (it > 9) break;
|
||||
if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset
|
||||
CJSON(timerHours[it], timer[F("hour")]);
|
||||
CJSON(timerMinutes[it], timer[F("min")]);
|
||||
CJSON(timerMacro[it], timer[F("macro")]);
|
||||
@@ -466,9 +471,10 @@ void serializeConfig() {
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
|
||||
ins[F("order")] = bus->getColorOrder();
|
||||
ins["rev"] = bus->reversed;
|
||||
ins[F("skip")] = (skipFirstLed && s == 0) ? 1 : 0;
|
||||
ins["rev"] = bus->reversed;
|
||||
ins[F("skip")] = bus->skipFirstLed();
|
||||
ins["type"] = bus->getType();
|
||||
ins[F("rgbw")] = bus->isRgbw();
|
||||
}
|
||||
|
||||
JsonObject hw_btn = hw.createNestedObject("btn");
|
||||
@@ -490,7 +496,7 @@ void serializeConfig() {
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
hw_ir["pin"] = irPin;
|
||||
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
#endif
|
||||
|
||||
JsonObject hw_relay = hw.createNestedObject(F("relay"));
|
||||
@@ -500,9 +506,6 @@ void serializeConfig() {
|
||||
//JsonObject hw_status = hw.createNestedObject("status");
|
||||
//hw_status["pin"] = -1;
|
||||
|
||||
JsonObject hw_aux = hw.createNestedObject("aux");
|
||||
hw_aux["pin"] = auxPin;
|
||||
|
||||
JsonObject light = doc.createNestedObject(F("light"));
|
||||
light[F("scale-bri")] = briMultiplier;
|
||||
light[F("pal-mode")] = strip.paletteBlend;
|
||||
@@ -620,6 +623,8 @@ void serializeConfig() {
|
||||
if_ntp[F("tz")] = currentTimezone;
|
||||
if_ntp[F("offset")] = utcOffsetSecs;
|
||||
if_ntp[F("ampm")] = useAMPM;
|
||||
if_ntp[F("ln")] = longitude;
|
||||
if_ntp[F("lt")] = latitude;
|
||||
|
||||
JsonObject ol = doc.createNestedObject("ol");
|
||||
ol[F("clock")] = overlayDefault;
|
||||
@@ -641,8 +646,8 @@ void serializeConfig() {
|
||||
|
||||
JsonArray timers_ins = timers.createNestedArray("ins");
|
||||
|
||||
for (byte i = 0; i < 8; i++) {
|
||||
if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue;
|
||||
for (byte i = 0; i < 10; i++) {
|
||||
if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; // sunrise/sunset get saved always (timerHours=255)
|
||||
JsonObject timers_ins0 = timers_ins.createNestedObject();
|
||||
timers_ins0["en"] = (timerWeekday[i] & 0x01);
|
||||
timers_ins0[F("hour")] = timerHours[i];
|
||||
|
||||
@@ -13,11 +13,13 @@
|
||||
//increase if you need more
|
||||
#define WLED_MAX_USERMODS 4
|
||||
|
||||
#ifndef WLED_MAX_BUSSES
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_BUSSES 3
|
||||
#else
|
||||
#define WLED_MAX_BUSSES 10
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Usermod IDs
|
||||
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
||||
@@ -115,10 +117,10 @@
|
||||
#define TYPE_LPD8806 52
|
||||
#define TYPE_P9813 53
|
||||
|
||||
#define IS_DIGITAL(t) (t & 0x10) //digital are 16-31 and 48-63
|
||||
#define IS_PWM(t) (t > 40 && t < 46)
|
||||
#define NUM_PWM_PINS(t) (t - 40) //for analog PWM 41-45 only
|
||||
#define IS_2PIN(t) (t > 47)
|
||||
#define IS_DIGITAL(t) ((t) & 0x10) //digital are 16-31 and 48-63
|
||||
#define IS_PWM(t) ((t) > 40 && (t) < 46)
|
||||
#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only
|
||||
#define IS_2PIN(t) ((t) > 47)
|
||||
|
||||
//Color orders
|
||||
#define COL_ORDER_GRB 0 //GRB(w),defaut
|
||||
@@ -188,7 +190,7 @@
|
||||
// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266
|
||||
#ifndef MAX_LEDS
|
||||
#ifdef ESP8266
|
||||
#define MAX_LEDS 8192 //rely on memory limit to limit this to 1600 LEDs
|
||||
#define MAX_LEDS 1664 // can't rely on memory limit to limit this to 1600 LEDs
|
||||
#else
|
||||
#define MAX_LEDS 8192
|
||||
#endif
|
||||
@@ -203,7 +205,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef MAX_LEDS_PER_BUS
|
||||
#define MAX_LEDS_PER_BUS 4096
|
||||
#define MAX_LEDS_PER_BUS 2048 // may not be enough for fast LEDs (i.e. APA102)
|
||||
#endif
|
||||
|
||||
// string temp buffer (now stored in stack locally)
|
||||
@@ -240,7 +242,11 @@
|
||||
|
||||
//this is merely a default now and can be changed at runtime
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 2
|
||||
#ifdef ESP8266
|
||||
#define LEDPIN 2 // GPIO2 (D4) on Wemod D1 mini compatible boards
|
||||
#else
|
||||
#define LEDPIN 16 // alligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,10 +23,10 @@
|
||||
<button id="buttonNl" onclick="toggleNl()"><i class="icons"></i><p class="tab-label">Timer</p></button>
|
||||
<button id="buttonSync" onclick="toggleSync()"><i class="icons"></i><p class="tab-label">Sync</p></button>
|
||||
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons"></i><p class="tab-label">Peek</p></button>
|
||||
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
||||
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button></div>
|
||||
<button onclick="window.location.href = '/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
||||
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
||||
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button></div>
|
||||
<button onclick="window.location.href='/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
||||
</div>
|
||||
<div id="briwrap">
|
||||
<p class="hd">Brightness</p>
|
||||
@@ -36,6 +36,7 @@
|
||||
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
</div>
|
||||
<iframe id="liveview" src="about:blank"></iframe>
|
||||
@@ -46,17 +47,26 @@
|
||||
<div id="Colors" class="tabcontent">
|
||||
<div id="picker" class="noslide"></div>
|
||||
<div id="rgbwrap">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderR" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,1)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<div id="rwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderR" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,1)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderG" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,2)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<div id="gwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderG" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,2)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderB" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,3)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<div id="bwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderB" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,3)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
</div>
|
||||
<div id="wwrap">
|
||||
@@ -64,6 +74,7 @@
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderW" class="noslide" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
</div>
|
||||
<div id="qcs-w">
|
||||
@@ -80,25 +91,27 @@
|
||||
<div class="qcs" onclick="pC('rnd');" title="Random" style="background-color:var(--c-3); padding: 4px 8px; transform: translateY(-10px);">R</div>
|
||||
</div>
|
||||
<div id="csl">
|
||||
<button class="xxs cl btn" onclick="selectSlot(0);">1</button>
|
||||
<button class="xxs cl btn" onclick="selectSlot(1);">2</button>
|
||||
<button class="xxs cl btn" onclick="selectSlot(2);">3</button>
|
||||
<button class="xxs btn" onclick="selectSlot(0);">1</button>
|
||||
<button class="xxs btn" onclick="selectSlot(1);">2</button>
|
||||
<button class="xxs btn" onclick="selectSlot(2);">3</button>
|
||||
</div>
|
||||
<div id="hexw">
|
||||
<input id="hexc" type="text" class="noslide" onkeydown="hexEnter(this)" autocomplete="off" maxlength="8" />
|
||||
<button id="hexcnf" class="xxs btn" onclick="fromHex();"><i class="icons btna-icon"></i></button>
|
||||
</div>
|
||||
<p class="labels">
|
||||
<i class="icons sel-icon" onclick="tglHex()"></i>
|
||||
Color palette
|
||||
</p>
|
||||
<p class="labels"><i class="icons sel-icon" onclick="tglHex()"></i> Color palette</p>
|
||||
<div class="il">
|
||||
<div class="staytop fnd">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'selectPalette')" onfocus="search(this)" />
|
||||
<span onclick="clean(this)" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<div id="selectPalette" class="list">
|
||||
<div class="lstI" data-id="0">
|
||||
<label class="check schkl">
|
||||
<label class="radio schkl">
|
||||
|
||||
<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()">
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="radiomark schk"></span>
|
||||
</label>
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
@@ -120,35 +133,41 @@
|
||||
|
||||
<div id="Effects" class="tabcontent">
|
||||
<p class="labels">Effect speed</p>
|
||||
<div class="staytop">
|
||||
<div class="staytop" id="staytop">
|
||||
<i class="icons slider-icon"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<p class="labels">Effect intensity</p>
|
||||
<div class="staytop" id="staytop1">
|
||||
<i class="icons slider-icon" onclick="tglLabels()"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderIntensity" class="noslide" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<p class="labels">Effect mode</p>
|
||||
<div id="fxlist" class="list">
|
||||
Loading...
|
||||
<div class="il">
|
||||
<p class="labels">Effect mode</p>
|
||||
<div class="staytop fnd" id="staytop2">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this)" />
|
||||
<span onclick="clean(this);" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<div id="fxlist" class="list">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="Segments" class="tabcontent">
|
||||
<div id="segutil" class="staytop">
|
||||
</div>
|
||||
<div id="segcont">
|
||||
Loading...
|
||||
</div>
|
||||
<div id="segutil">
|
||||
|
||||
</div>
|
||||
<div id="segutil2">
|
||||
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
||||
@@ -156,16 +175,14 @@
|
||||
</div>
|
||||
|
||||
<div id="Favorites" class="tabcontent">
|
||||
<div id="putil">
|
||||
|
||||
<div id="putil" class="staytop">
|
||||
</div>
|
||||
<div id="pql">
|
||||
|
||||
</div>
|
||||
<div id="pcont">
|
||||
Loading...
|
||||
</div><br>
|
||||
<label class="check psvl">
|
||||
<label class="check psvl">
|
||||
Preset cycle
|
||||
<input type="checkbox" id="cyToggle" onchange="toggleCY()">
|
||||
<span class="checkmark psv"></span>
|
||||
@@ -173,7 +190,7 @@
|
||||
First preset: <input id="cycs" class="noslide" type="number" min="1" max="249" value="1"><br>
|
||||
Last preset: <input id="cyce" class="noslide" type="number" min="2" max="250" value="3"><br>
|
||||
Time per preset: <input id="cyct" class="noslide" type="number" min="0.2" max="6553.5" step="0.1" value="1.2">s<br>
|
||||
Transition: <input id="cyctt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s
|
||||
Transition: <input id="cyctt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s<br><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -182,6 +199,7 @@
|
||||
<button class="tablinks" onclick="openTab(1)"><i class="icons"></i><p class="tab-label">Effects</p></button>
|
||||
<button class="tablinks" onclick="openTab(2)"><i class="icons"></i><p class="tab-label">Segments</p></button>
|
||||
<button class="tablinks" onclick="openTab(3)"><i class="icons"></i><p class="tab-label">Favorites</p></button>
|
||||
<!--button class="tablinks" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button-->
|
||||
</div>
|
||||
|
||||
<div id="connind"></div>
|
||||
@@ -191,19 +209,19 @@
|
||||
<div id="imgw">
|
||||
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAggAAACMCAYAAAAZQlGEAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKLSURBVHhe7dgxjtwwEADBpf//5zUDwklnpzFAnKoSTigNFTT0AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDcOieX+G5nvNLaznil6f1Nv+/tz3c7+3tmen/Tpu/jbe877c85AQD+EQgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAINY5+aHvdsYRazvjK9jfM7fvz/0+Y3+/2+336w8CABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAADEOudrfLczXmltZ3yF6fuwv2em9+d+n5ne3zT3cZfp+/AHAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAYp3zNb7bGUes7Yz8wO334fmeuf35bmd/z9y+v9ufzx8EACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAIAQCABACAQCIdc4x3+2MV1rbGfmFpr+/6e/l9ue73fT+pt1+H2/bn+/lGX8QAIAQCABACAQAIAQCABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgP/u8/kLYCqAxINTyZkAAAAASUVORK5CYII=">
|
||||
</div><br>
|
||||
<div id="kv">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="requestJson(null)">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
|
||||
<span class="h">Made with <span id="heart">❤︎</span> by Aircoookie and the WLED community</span>
|
||||
<div id="kv">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="loadInfo()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
|
||||
<span class="h">Made with <span id="heart">❤︎</span> by Aircoookie and the WLED community</span>
|
||||
</div>
|
||||
|
||||
<div id="nodes" class="modal">
|
||||
<div id="ndlt">WLED instances</div>
|
||||
<div id="kn">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
|
||||
<div id="ndlt">WLED instances</div>
|
||||
<div id="kn">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
|
||||
</div>
|
||||
|
||||
<div id="rover" class="modal">
|
||||
|
||||
1691
wled00/data/index.js
1691
wled00/data/index.js
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@
|
||||
|
||||
socket.onopen = function () {
|
||||
console.info("Live-Preview websocket is opened");
|
||||
socket.send("{'lv':true}");
|
||||
socket.send("{'lv':true,'rev':2}");
|
||||
}
|
||||
|
||||
socket.onclose = function () { console.info("Live-Preview websocket is closing"); }
|
||||
|
||||
@@ -37,8 +37,10 @@ function GetV(){}
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>Imma firin ma lazer (if it has DMX support)</h2><!-- TODO: Change to something less-meme-related //-->
|
||||
|
||||
Proxy Universe <input name=PU type=number min=0 max=63999 required> from E1.31 to DMX (0=disabled)<br>
|
||||
|
||||
@@ -1,350 +1,377 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=500">
|
||||
<title>LED Settings</title>
|
||||
<script>
|
||||
var d=document,laprev=55,maxB=1,maxM=5000,maxPB=4096,bquot=0; //maximum bytes for LED allocation: 5kB for 8266, 32kB for 32
|
||||
function H()
|
||||
{
|
||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");
|
||||
}
|
||||
function B()
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
}
|
||||
function bLimits(b,p,m) {
|
||||
maxB = b; maxM = m; maxPB = p;
|
||||
}
|
||||
function trySubmit() {
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
|
||||
//check for pin conflicts
|
||||
if (nm=="L0" || nm=="L1" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX")
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].focus();return;}
|
||||
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert("Usermod pin conflict!");LCs[i].focus();return;}
|
||||
for (j=i+1; j<LCs.length; j++)
|
||||
{
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="RL" || n2=="BT" || n2=="IR" || n2=="AX")
|
||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert("Pin conflict!");LCs[i].focus();return;}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += " Consider using an ESP32."; alert(msg); return;}
|
||||
if (d.Sf.reportValidity()) d.Sf.submit();
|
||||
}
|
||||
function S(){GetV();setABL();}
|
||||
function enABL()
|
||||
{
|
||||
var en = d.getElementById('able').checked;
|
||||
d.Sf.LA.value = (en) ? laprev:0;
|
||||
d.getElementById('abl').style.display = (en) ? 'inline':'none';
|
||||
d.getElementById('psu2').style.display = (en) ? 'inline':'none';
|
||||
if (d.Sf.LA.value > 0) setABL();
|
||||
}
|
||||
function enLA()
|
||||
{
|
||||
var val = d.Sf.LAsel.value;
|
||||
d.Sf.LA.value = val;
|
||||
d.getElementById('LAdis').style.display = (val == 50) ? 'inline':'none';
|
||||
UI();
|
||||
}
|
||||
function setABL()
|
||||
{
|
||||
d.getElementById('able').checked = true;
|
||||
d.Sf.LAsel.value = 50;
|
||||
switch (parseInt(d.Sf.LA.value)) {
|
||||
case 0: d.getElementById('able').checked = false; enABL(); break;
|
||||
case 30: d.Sf.LAsel.value = 30; break;
|
||||
case 35: d.Sf.LAsel.value = 35; break;
|
||||
case 55: d.Sf.LAsel.value = 55; break;
|
||||
case 255: d.Sf.LAsel.value = 255; break;
|
||||
default: d.getElementById('LAdis').style.display = 'inline';
|
||||
}
|
||||
d.getElementById('m1').innerHTML = maxM;
|
||||
UI();
|
||||
}
|
||||
//returns mem usage
|
||||
function getMem(type, len, p0) {
|
||||
//len = parseInt(len);
|
||||
if (type < 32) {
|
||||
if (maxM < 10000 && p0 ==3) { //8266 DMA uses 5x the mem
|
||||
if (type > 29) return len*20; //RGBW
|
||||
return len*15;
|
||||
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
||||
{
|
||||
if (type > 29) return len*8; //RGBW
|
||||
return len*6;
|
||||
}
|
||||
if (type > 29) return len*4; //RGBW
|
||||
return len*3;
|
||||
}
|
||||
if (type > 31 && type < 48) return 5;
|
||||
if (type == 44 || type == 45) return len*4; //RGBW
|
||||
return len*3;
|
||||
}
|
||||
function UI()
|
||||
{
|
||||
var isRGBW = false, memu = 0;
|
||||
|
||||
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
|
||||
|
||||
if (d.Sf.LA.value == 255) laprev = 12;
|
||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||
|
||||
var s = d.getElementsByTagName("select");
|
||||
for (i=0; i<s.length; i++) {
|
||||
if (s[i].name.substring(0,2)=="LT") {
|
||||
n=s[i].name.substring(2);
|
||||
var type = s[i].value;
|
||||
d.getElementById("p0d"+n).innerHTML = (type > 49) ? "Data pin:" : (type >41) ? "Pins:" : "Pin:";
|
||||
d.getElementById("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
|
||||
var LK = d.getElementsByName("L1"+n)[0];
|
||||
|
||||
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value);
|
||||
|
||||
for (p=1; p<5; p++) {
|
||||
var LK = d.getElementsByName("L"+p+n)[0];
|
||||
if (!LK) continue;
|
||||
if ((type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
|
||||
{
|
||||
LK.style.display = "inline";
|
||||
LK.required = true;
|
||||
} else {
|
||||
LK.style.display = "none";
|
||||
LK.required = false;
|
||||
LK.value="";
|
||||
}
|
||||
}
|
||||
if (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)) isRGBW = true;
|
||||
d.getElementById("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
|
||||
d.getElementById("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
|
||||
}
|
||||
}
|
||||
|
||||
var myC = d.querySelectorAll('.wc'),
|
||||
l = myC.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
myC[i].style.display = (isRGBW) ? 'inline':'none';
|
||||
}
|
||||
|
||||
if (d.activeElement == d.getElementsByName("LC")[0]) {
|
||||
var o = d.getElementsByClassName("iST");
|
||||
var i = o.length;
|
||||
if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
|
||||
}
|
||||
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
var sLC = 0, maxLC = 0;
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
if (nm=="LC" && LCs[i].name != "LC") {var c = parseInt(LCs[i].value,10); if (c) {sLC+=c; if (c>maxLC) maxLC = c;} continue;}
|
||||
}
|
||||
|
||||
d.getElementById('m0').innerHTML = memu;
|
||||
bquot = memu / maxM * 100;
|
||||
d.getElementById('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? bquot > 90 ? "red":"orange":"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
|
||||
d.getElementById('ledwarning').style.display = (maxLC > 800 || bquot > 80) ? 'inline':'none';
|
||||
//TODO add warning "Recommended pins on ESP8266 are 1 and 2 (3 only with low LED count)"
|
||||
//TODO add overmemory warning
|
||||
//TODO block disallowed pins 6-11
|
||||
d.getElementById('wreason').innerHTML = (bquot > 80) ? "than 60%% of max. LED memory" : "800 LEDs per pin";
|
||||
|
||||
//var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2;
|
||||
var val = Math.ceil((100 + sLC * laprev)/500)/2;
|
||||
val = (val > 5) ? Math.ceil(val) : val;
|
||||
var s = "";
|
||||
var is12V = (d.Sf.LAsel.value == 30);
|
||||
var isWS2815 = (d.Sf.LAsel.value == 255);
|
||||
if (val < 1.02 && !is12V && !isWS2815)
|
||||
{
|
||||
s = "ESP 5V pin with 1A USB supply";
|
||||
} else
|
||||
{
|
||||
s += is12V ? "12V ": isWS2815 ? "WS2815 12V " : "5V ";
|
||||
s += val;
|
||||
s += "A supply connected to LEDs";
|
||||
}
|
||||
var val2 = Math.ceil((100 + sLC * laprev)/1500)/2;
|
||||
val2 = (val2 > 5) ? Math.ceil(val2) : val2;
|
||||
var s2 = "(for most effects, ~";
|
||||
s2 += val2;
|
||||
s2 += "A is enough)<br>";
|
||||
d.getElementById('psu').innerHTML = s;
|
||||
d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2;
|
||||
}
|
||||
function lastEnd(i) {
|
||||
if (i<1) return 0;
|
||||
v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value);
|
||||
if (isNaN(v)) return 0;
|
||||
return v;
|
||||
}
|
||||
function addLEDs(n)
|
||||
{
|
||||
if (n>1) {maxB=n; d.getElementById("+").style.display="inline"; return;}
|
||||
|
||||
var o = d.getElementsByClassName("iST");
|
||||
var i = o.length;
|
||||
|
||||
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
|
||||
|
||||
var f = d.getElementById("mLC");
|
||||
if (n==1) {
|
||||
var cn = `<div class="iST">
|
||||
${i>0?'<hr style="width:260px">':''}
|
||||
${i+1}:
|
||||
<select name="LT${i}" onchange="UI()">
|
||||
<option value="22">WS281x</option>
|
||||
<option value="30">SK6812 RGBW</option>
|
||||
<option value="31">TM1814</option>
|
||||
<option value="24">400kHz</option>
|
||||
<option value="50">WS2801</option>
|
||||
<option value="51">APA102</option>
|
||||
<option value="52">LPD8806</option>
|
||||
<option value="53">P9813</option>
|
||||
<option value="41">PWM White</option>
|
||||
<option value="42">PWM WWCW</option>
|
||||
<option value="43">PWM RGB</option>
|
||||
<option value="44">PWM RGBW</option>
|
||||
<option value="45">PWM RGBWC</option>
|
||||
</select>
|
||||
Color Order:
|
||||
<select name="CO${i}">
|
||||
<option value="0">GRB</option>
|
||||
<option value="1">RGB</option>
|
||||
<option value="2">BRG</option>
|
||||
<option value="3">RBG</option>
|
||||
<option value="4">BGR</option>
|
||||
<option value="5">GBR</option>
|
||||
</select><br>
|
||||
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" oninput="UI()"/>
|
||||
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px"/>
|
||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px"/>
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px"/>
|
||||
<br>
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" min="0" max="8191" value="${lastEnd(i)}" required />
|
||||
<div id="dig${i}" style="display:inline">
|
||||
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br></div>
|
||||
Reverse: <input type="checkbox" name="CV${i}"><br>
|
||||
</div>`;
|
||||
f.insertAdjacentHTML("beforeend", cn);
|
||||
}
|
||||
if (n==-1) {
|
||||
o[--i].remove();--i;
|
||||
}
|
||||
|
||||
d.getElementById("+").style.display = (i<maxB-1) ? "inline":"none";
|
||||
d.getElementById("-").style.display = (i>0) ? "inline":"none";
|
||||
|
||||
UI();
|
||||
}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
//d.um_p=[];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RV.checked=0;d.Sf.SL.checked=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;d.Sf.BT.value=-1;d.Sf.IR.value=-1;d.Sf.AX.value=-1;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="trySubmit()">Save</button><hr>
|
||||
<h2>LED & Hardware setup</h2>
|
||||
Total LED count: <input name="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id="psu">?</span></b><br>
|
||||
<span id="psu2"><br></span>
|
||||
<br>
|
||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||
<div id="abl">
|
||||
Maximum Current: <input name="MA" type="number" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
<div id="ampwarning" style="color: orange; display: none;">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
multiple power injection points and a fuse!<br>
|
||||
</div>
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If you are using an external power supply, enter its rating.<br>
|
||||
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
||||
LED voltage (Max. current for a single LED):<br>
|
||||
<select name="LAsel" onchange="enLA()">
|
||||
<option value="55" selected>5V default (55mA)</option>
|
||||
<option value="35">5V efficient (35mA)</option>
|
||||
<option value="30">12V (30mA)</option>
|
||||
<option value="255">WS2815 (12mA)</option>
|
||||
<option value="50">Custom</option>
|
||||
</select><br>
|
||||
<span id="LAdis" style="display: none;">Custom max. current per LED: <input name="LA" type="number" min="0" max="255" id="la" oninput="UI()" required> mA<br></span>
|
||||
<i>Keep at default if you are unsure about your type of LEDs.</i><br>
|
||||
</div>
|
||||
<h3>Hardware setup</h3>
|
||||
<div id="mLC">LED outputs:</div>
|
||||
<button type="button" id="+" onclick="addLEDs(1)" style="display:none;border-radius:20px;height:36px;">+</button>
|
||||
<button type="button" id="-" onclick="addLEDs(-1)" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
|
||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||
<div id="ledwarning" style="color: orange; display: none;">
|
||||
⚠ You might run into stability or lag issues.<br>
|
||||
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
|
||||
</div><br>
|
||||
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"> Active high <input type="checkbox" name="RM"><br>
|
||||
Button pin: <input type="number" min="-1" max="40" name="BT" onchange="UI()"><br>
|
||||
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><br>
|
||||
AUX pin: <input type="number" min="-1" max="40" name="AX" onchange="UI()">
|
||||
<h3>Defaults</h3>
|
||||
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
|
||||
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br>
|
||||
Apply preset <input name="BP" type="number" min="0" max="250" required> at boot (0 uses defaults)
|
||||
<br>- <i>or</i> -<br>
|
||||
Set current preset cycle setting as boot default: <input type="checkbox" name="PC"><br><br>
|
||||
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
|
||||
Brightness factor: <input name="BF" type="number" min="1" max="255" required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type="checkbox" name="TF"><br>
|
||||
Transition Time: <input name="TD" maxlength="5" size="2"> ms<br>
|
||||
Enable Palette transitions: <input type="checkbox" name="PF">
|
||||
<h3>Timed light</h3>
|
||||
Default Duration: <input name="TL" type="number" min="1" max="255" required> min<br>
|
||||
Default Target brightness: <input name="TB" type="number" min="0" max="255" required><br>
|
||||
Mode:
|
||||
<select name="TW">
|
||||
<option value="0">Wait and set</option>
|
||||
<option value="1">Fade</option>
|
||||
<option value="2">Fade Color</option>
|
||||
<option value="3">Sunrise</option>
|
||||
</select>
|
||||
<h3>Advanced</h3>
|
||||
Palette blending:
|
||||
<select name="PB">
|
||||
<option value="0">Linear (wrap if moving)</option>
|
||||
<option value="1">Linear (always wrap)</option>
|
||||
<option value="2">Linear (never wrap)</option>
|
||||
<option value="3">None (not recommended)</option>
|
||||
</select><br>
|
||||
Skip first LED: <input type="checkbox" name="SL"><br>
|
||||
<span class="wc">
|
||||
Auto-calculate white channel from RGB:<br>
|
||||
<select name="AW">
|
||||
<option value=0>None</option>
|
||||
<option value=1>Brighter</option>
|
||||
<option value=2>Accurate</option>
|
||||
<option value=3>Dual</option>
|
||||
<option value=4>Legacy</option>
|
||||
</select>
|
||||
<br></span><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="trySubmit()">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=500">
|
||||
<title>LED Settings</title>
|
||||
<script>
|
||||
var d=document,laprev=55,maxB=1,maxM=5000,maxPB=4096,bquot=0; //maximum bytes for LED allocation: 5kB for 8266, 32kB for 32
|
||||
function H()
|
||||
{
|
||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");
|
||||
}
|
||||
function B()
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
}
|
||||
function off(n){
|
||||
d.getElementsByName(n)[0].value = -1;
|
||||
}
|
||||
function bLimits(b,p,m) {
|
||||
maxB = b; maxM = m; maxPB = p;
|
||||
}
|
||||
function pinsOK() {
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
//check for pin conflicts
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX")
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.um_p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;}
|
||||
else if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].value="";LCs[i].focus();return false;}
|
||||
for (j=i+1; j<LCs.length; j++)
|
||||
{
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR" || n2=="AX")
|
||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${nm}/${n2}!`);LCs[j].value="";LCs[j].focus();return false;}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function trySubmit(e) {
|
||||
e.preventDefault();
|
||||
if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server
|
||||
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
|
||||
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
|
||||
}
|
||||
function S(){GetV();setABL();}
|
||||
function enABL()
|
||||
{
|
||||
var en = d.getElementById('able').checked;
|
||||
d.Sf.LA.value = (en) ? laprev:0;
|
||||
d.getElementById('abl').style.display = (en) ? 'inline':'none';
|
||||
d.getElementById('psu2').style.display = (en) ? 'inline':'none';
|
||||
if (d.Sf.LA.value > 0) setABL();
|
||||
}
|
||||
function enLA()
|
||||
{
|
||||
var val = d.Sf.LAsel.value;
|
||||
d.Sf.LA.value = val;
|
||||
d.getElementById('LAdis').style.display = (val == 50) ? 'inline':'none';
|
||||
UI();
|
||||
}
|
||||
function setABL()
|
||||
{
|
||||
d.getElementById('able').checked = true;
|
||||
d.Sf.LAsel.value = 50;
|
||||
switch (parseInt(d.Sf.LA.value)) {
|
||||
case 0: d.getElementById('able').checked = false; enABL(); break;
|
||||
case 30: d.Sf.LAsel.value = 30; break;
|
||||
case 35: d.Sf.LAsel.value = 35; break;
|
||||
case 55: d.Sf.LAsel.value = 55; break;
|
||||
case 255: d.Sf.LAsel.value = 255; break;
|
||||
default: d.getElementById('LAdis').style.display = 'inline';
|
||||
}
|
||||
d.getElementById('m1').innerHTML = maxM;
|
||||
d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
|
||||
UI();
|
||||
}
|
||||
//returns mem usage
|
||||
function getMem(type, len, p0) {
|
||||
//len = parseInt(len);
|
||||
if (type < 32) {
|
||||
if (maxM < 10000 && p0==3) { //8266 DMA uses 5x the mem
|
||||
if (type > 29) return len*20; //RGBW
|
||||
return len*15;
|
||||
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
||||
{
|
||||
if (type > 29) return len*8; //RGBW
|
||||
return len*6;
|
||||
}
|
||||
if (type > 29) return len*4; //RGBW
|
||||
return len*3;
|
||||
}
|
||||
if (type > 31 && type < 48) return 5;
|
||||
if (type == 44 || type == 45) return len*4; //RGBW
|
||||
return len*3;
|
||||
}
|
||||
function UI(change=false)
|
||||
{
|
||||
var isRGBW = false, memu = 0;
|
||||
|
||||
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
|
||||
|
||||
if (d.Sf.LA.value == 255) laprev = 12;
|
||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||
|
||||
var s = d.getElementsByTagName("select");
|
||||
for (i=0; i<s.length; i++) {
|
||||
if (s[i].name.substring(0,2)=="LT") {
|
||||
n=s[i].name.substring(2);
|
||||
var type = parseInt(s[i].value,10);
|
||||
d.getElementById("p0d"+n).innerHTML = (type > 49) ? "Data:" : (type >41) ? "Pins:" : "Pin:";
|
||||
d.getElementById("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
|
||||
var LK = d.getElementsByName("L1"+n)[0];
|
||||
|
||||
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value);
|
||||
|
||||
for (p=1; p<5; p++) {
|
||||
var LK = d.getElementsByName("L"+p+n)[0];
|
||||
if (!LK) continue;
|
||||
if ((type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
|
||||
{
|
||||
LK.style.display = "inline";
|
||||
LK.required = true;
|
||||
} else {
|
||||
LK.style.display = "none";
|
||||
LK.required = false;
|
||||
LK.value="";
|
||||
}
|
||||
}
|
||||
d.getElementById("ls"+n).readOnly = !(type > 31 && type < 48); // not analog
|
||||
d.getElementById("LC").readOnly = !(type > 31 && type < 48); // not analog
|
||||
if (change) {
|
||||
d.getElementById("ew"+n).checked = (type == 30 || type == 31 || type == 44 || type == 45); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
d.getElementById("ls"+n).value = n+1;
|
||||
}
|
||||
d.getElementById("ew"+n).onclick = (type > 31 && type < 48) ? (function(){return false}) : (function(){}); // prevent change for analog
|
||||
isRGBW |= d.getElementById("ew"+n).checked;
|
||||
d.getElementById("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
|
||||
d.getElementById("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
|
||||
}
|
||||
}
|
||||
|
||||
var myC = d.querySelectorAll('.wc'),
|
||||
l = myC.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
myC[i].style.display = (isRGBW) ? 'inline':'none';
|
||||
}
|
||||
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
var sLC = 0, maxLC = 0;
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
if (nm=="LC" && LCs[i].name !== "LC") {
|
||||
var n=LCs[i].name.substring(2);
|
||||
var c=parseInt(LCs[i].value,10);
|
||||
if(d.getElementById("ls"+n).readOnly) d.getElementById("ls"+n).value=sLC;
|
||||
if(c){sLC+=c;if(c>maxLC)maxLC=c;}
|
||||
continue;
|
||||
}
|
||||
if (nm=="L0" || nm=="L1") {
|
||||
var lc=d.getElementsByName("LC"+LCs[i].name.substring(2))[0];
|
||||
lc.max=maxPB;
|
||||
}
|
||||
}
|
||||
|
||||
if (d.getElementById("LC").readOnly) d.getElementsByName("LC")[0].value = sLC;
|
||||
if (d.activeElement == d.getElementsByName("LC")[0]) {
|
||||
var o = d.getElementsByClassName("iST");
|
||||
var i = o.length;
|
||||
if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
|
||||
}
|
||||
d.getElementById('m0').innerHTML = memu;
|
||||
bquot = memu / maxM * 100;
|
||||
d.getElementById('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
|
||||
d.getElementById('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none';
|
||||
d.getElementById('ledwarning').style.color = (sLC > maxPB || maxLC > maxPB || bquot > 100) ? 'red':'orange';
|
||||
d.getElementById('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>WARNING: Using over ${maxM}B!</b>)` : "") : "800 LEDs per pin";
|
||||
|
||||
var val = Math.ceil((100 + sLC * laprev)/500)/2;
|
||||
val = (val > 5) ? Math.ceil(val) : val;
|
||||
var s = "";
|
||||
var is12V = (d.Sf.LAsel.value == 30);
|
||||
var isWS2815 = (d.Sf.LAsel.value == 255);
|
||||
if (val < 1.02 && !is12V && !isWS2815)
|
||||
{
|
||||
s = "ESP 5V pin with 1A USB supply";
|
||||
} else
|
||||
{
|
||||
s += is12V ? "12V ": isWS2815 ? "WS2815 12V " : "5V ";
|
||||
s += val;
|
||||
s += "A supply connected to LEDs";
|
||||
}
|
||||
var val2 = Math.ceil((100 + sLC * laprev)/1500)/2;
|
||||
val2 = (val2 > 5) ? Math.ceil(val2) : val2;
|
||||
var s2 = "(for most effects, ~";
|
||||
s2 += val2;
|
||||
s2 += "A is enough)<br>";
|
||||
d.getElementById('psu').innerHTML = s;
|
||||
d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2;
|
||||
}
|
||||
function lastEnd(i) {
|
||||
if (i<1) return 0;
|
||||
v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value);
|
||||
if (isNaN(v)) return 0;
|
||||
return v;
|
||||
}
|
||||
function addLEDs(n)
|
||||
{
|
||||
if (n>1) {maxB=n; d.getElementById("+").style.display="inline"; return;}
|
||||
|
||||
var o = d.getElementsByClassName("iST");
|
||||
var i = o.length;
|
||||
|
||||
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
|
||||
|
||||
var f = d.getElementById("mLC");
|
||||
if (n==1) {
|
||||
// npm run build has trouble minimizing spaces inside string
|
||||
var cn = `<div class="iST">
|
||||
${i>0?'<hr style="width:260px">':''}
|
||||
${i+1}:
|
||||
<select name="LT${i}" onchange="UI(true)">
|
||||
<option value="22">WS281x</option>
|
||||
<option value="30">SK6812 RGBW</option>
|
||||
<option value="31">TM1814</option>
|
||||
<option value="24">400kHz</option>
|
||||
<option value="50">WS2801</option>
|
||||
<option value="51">APA102</option>
|
||||
<option value="52">LPD8806</option>
|
||||
<option value="53">P9813</option>
|
||||
<option value="41">PWM White</option>
|
||||
<option value="42">PWM WWCW</option>
|
||||
<option value="43">PWM RGB</option>
|
||||
<option value="44">PWM RGBW</option>
|
||||
<option value="45">PWM RGBWC</option>
|
||||
</select>
|
||||
Color Order:
|
||||
<select name="CO${i}">
|
||||
<option value="0">GRB</option>
|
||||
<option value="1">RGB</option>
|
||||
<option value="2">BRG</option>
|
||||
<option value="3">RBG</option>
|
||||
<option value="4">BGR</option>
|
||||
<option value="5">GBR</option>
|
||||
</select><br>
|
||||
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" onchange="UI()"/>
|
||||
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<br>
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" min="0" max="8191" value="${lastEnd(i)}" required />
|
||||
<div id="dig${i}" style="display:inline">
|
||||
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
|
||||
Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
</div>
|
||||
RGBW: <input id="ew${i}" type="checkbox" name="EW${i}"><br>
|
||||
</div>`;
|
||||
f.insertAdjacentHTML("beforeend", cn);
|
||||
}
|
||||
if (n==-1) {
|
||||
o[--i].remove();--i;
|
||||
}
|
||||
|
||||
d.getElementById("+").style.display = (i<maxB-1) ? "inline":"none";
|
||||
d.getElementById("-").style.display = (i>0) ? "inline":"none";
|
||||
|
||||
UI();
|
||||
}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
//maxM=5000;maxPB=1536;d.um_p=[1,6,7,8,9,10,11];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.SL.checked=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;d.Sf.BT.value=-1;d.Sf.IR.value=-1;d.Sf.AX.value=-1;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>LED & Hardware setup</h2>
|
||||
Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" required readonly><br>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id="psu">?</span></b><br>
|
||||
<span id="psu2"><br></span>
|
||||
<br>
|
||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||
<div id="abl">
|
||||
Maximum Current: <input name="MA" type="number" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
<div id="ampwarning" style="color: orange; display: none;">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
multiple power injection points and a fuse!<br>
|
||||
</div>
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If you are using an external power supply, enter its rating.<br>
|
||||
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
||||
LED voltage (Max. current for a single LED):<br>
|
||||
<select name="LAsel" onchange="enLA()">
|
||||
<option value="55" selected>5V default (55mA)</option>
|
||||
<option value="35">5V efficient (35mA)</option>
|
||||
<option value="30">12V (30mA)</option>
|
||||
<option value="255">WS2815 (12mA)</option>
|
||||
<option value="50">Custom</option>
|
||||
</select><br>
|
||||
<span id="LAdis" style="display: none;">Custom max. current per LED: <input name="LA" type="number" min="0" max="255" id="la" oninput="UI()" required> mA<br></span>
|
||||
<i>Keep at default if you are unsure about your type of LEDs.</i><br>
|
||||
</div>
|
||||
<h3>Hardware setup</h3>
|
||||
<div id="mLC">LED outputs:</div>
|
||||
<button type="button" id="+" onclick="addLEDs(1)">+</button>
|
||||
<button type="button" id="-" onclick="addLEDs(-1)">-</button><br>
|
||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||
<div id="ledwarning" style="color: orange; display: none;">
|
||||
⚠ You might run into stability or lag issues.<br>
|
||||
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
|
||||
</div><hr style="width:260px">
|
||||
Button pin: <input type="number" min="-1" max="40" name="BT" onchange="UI()"><span style="cursor: pointer;" onclick="off('BT')"> ×</span><br>
|
||||
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><span style="cursor: pointer;" onclick="off('IR')"> ×</span><br>
|
||||
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"><span style="cursor: pointer;" onclick="off('RL')"> ×</span><br>
|
||||
Active high <input type="checkbox" name="RM">
|
||||
<h3>Defaults</h3>
|
||||
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
|
||||
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br>
|
||||
Apply preset <input name="BP" type="number" min="0" max="250" required> at boot (0 uses defaults)
|
||||
<br>- <i>or</i> -<br>
|
||||
Set current preset cycle setting as boot default: <input type="checkbox" name="PC"><br><br>
|
||||
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
|
||||
Brightness factor: <input name="BF" type="number" min="1" max="255" required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type="checkbox" name="TF"><br>
|
||||
Transition Time: <input name="TD" maxlength="5" size="2"> ms<br>
|
||||
Enable Palette transitions: <input type="checkbox" name="PF">
|
||||
<h3>Timed light</h3>
|
||||
Default Duration: <input name="TL" type="number" min="1" max="255" required> min<br>
|
||||
Default Target brightness: <input name="TB" type="number" min="0" max="255" required><br>
|
||||
Mode:
|
||||
<select name="TW">
|
||||
<option value="0">Wait and set</option>
|
||||
<option value="1">Fade</option>
|
||||
<option value="2">Fade Color</option>
|
||||
<option value="3">Sunrise</option>
|
||||
</select>
|
||||
<h3>Advanced</h3>
|
||||
Palette blending:
|
||||
<select name="PB">
|
||||
<option value="0">Linear (wrap if moving)</option>
|
||||
<option value="1">Linear (always wrap)</option>
|
||||
<option value="2">Linear (never wrap)</option>
|
||||
<option value="3">None (not recommended)</option>
|
||||
</select><br>
|
||||
Skip first LED: <input type="checkbox" name="SL"><br>
|
||||
<span class="wc">
|
||||
Auto-calculate white channel from RGB:<br>
|
||||
<select name="AW">
|
||||
<option value=0>None</option>
|
||||
<option value=1>Brighter</option>
|
||||
<option value=2>Accurate</option>
|
||||
<option value=3>Dual</option>
|
||||
<option value=4>Legacy</option>
|
||||
</select>
|
||||
<br></span><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
</head>
|
||||
<body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
|
||||
</div>
|
||||
<h2>Security & Update setup</h2>
|
||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
||||
|
||||
@@ -12,8 +12,10 @@ function GetV(){var d=document;}
|
||||
<style>@import url("style.css");</style></head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>Sync setup</h2>
|
||||
<h3>Button setup</h3>
|
||||
On/Off button enabled: <input type="checkbox" name="BT"><br>
|
||||
@@ -32,7 +34,7 @@ Infrared remote:
|
||||
<h3>WLED Broadcast</h3>
|
||||
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
||||
2nd Port: <input name="U2" type="number" min="1" max="65535" class="d5" required><br>
|
||||
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
|
||||
Receive: <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
|
||||
Send notifications on direct change: <input type="checkbox" name="SD"><br>
|
||||
Send notifications on button press or IR: <input type="checkbox" name="SB"><br>
|
||||
Send Alexa notifications: <input type="checkbox" name="SA"><br>
|
||||
|
||||
@@ -6,62 +6,66 @@
|
||||
<title>Time Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
function H()
|
||||
function H()
|
||||
{
|
||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");
|
||||
}
|
||||
function B()
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
}
|
||||
function S()
|
||||
{
|
||||
BTa();GetV();Cs();FC();
|
||||
}
|
||||
function gId(s)
|
||||
{
|
||||
return d.getElementById(s);
|
||||
}
|
||||
function Cs()
|
||||
{
|
||||
gId("cac").style.display="none";
|
||||
gId("coc").style.display="block";
|
||||
gId("ccc").style.display="none";
|
||||
if (gId("ca").selected)
|
||||
{
|
||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");
|
||||
gId("cac").style.display="block";
|
||||
}
|
||||
function B()
|
||||
if (gId("cc").selected)
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
gId("coc").style.display="none";
|
||||
gId("ccc").style.display="block";
|
||||
}
|
||||
function S()
|
||||
if (gId("cn").selected)
|
||||
{
|
||||
BTa();GetV();Cs();FC();
|
||||
}
|
||||
function gId(s)
|
||||
{
|
||||
return d.getElementById(s);
|
||||
}
|
||||
function Cs()
|
||||
{
|
||||
gId("cac").style.display="none";
|
||||
gId("coc").style.display="block";
|
||||
gId("ccc").style.display="none";
|
||||
if (gId("ca").selected)
|
||||
{
|
||||
gId("cac").style.display="block";
|
||||
}
|
||||
if (gId("cc").selected)
|
||||
{
|
||||
gId("coc").style.display="none";
|
||||
gId("ccc").style.display="block";
|
||||
}
|
||||
if (gId("cn").selected)
|
||||
{
|
||||
gId("coc").style.display="none";
|
||||
}
|
||||
gId("coc").style.display="none";
|
||||
}
|
||||
}
|
||||
function BTa()
|
||||
{
|
||||
var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" class=\"small\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" class=\"small\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" class=\"small\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";
|
||||
}
|
||||
ih+="<tr><td><input name=\"W8\" id=\"W8\" type=\"number\" style=\"display:none\"><input id=\"W80\" type=\"checkbox\"></td><td>Sunrise<input name=\"H8\" class=\"small\" value=\"255\" type=\"hidden\"></td><td><input name=\"N8\" class=\"small\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T8\" class=\"small\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W8"+j+"\" type=\"checkbox\"></td>";
|
||||
ih+="<tr><td><input name=\"W9\" id=\"W9\" type=\"number\" style=\"display:none\"><input id=\"W90\" type=\"checkbox\"></td><td>Sunset<input name=\"H9\" class=\"small\" value=\"255\" type=\"hidden\"></td><td><input name=\"N9\" class=\"small\" type=\"number\" min=\"-59\" max=\"59\"><td><input name=\"T9\" class=\"small\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W9"+j+"\" type=\"checkbox\"></td>";
|
||||
gId("TMT").innerHTML=ih;
|
||||
}
|
||||
function FC()
|
||||
{
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
for(i=0;i<8;i++) gId("W"+i+j).checked=gId("W"+i).value>>j&1;
|
||||
for(i=0;i<10;i++) gId("W"+i+j).checked=gId("W"+i).value>>j&1;
|
||||
}
|
||||
}
|
||||
function Wd()
|
||||
{
|
||||
a=[0,0,0,0,0,0,0,0];
|
||||
for(i=0;i<8;i++)
|
||||
a=[0,0,0,0,0,0,0,0,0,0];
|
||||
for(i=0;i<10;i++)
|
||||
{
|
||||
m=1;
|
||||
for(j=0;j<8;j++)
|
||||
@@ -71,10 +75,10 @@
|
||||
gId("W"+i).value=a[i];
|
||||
}
|
||||
}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
@@ -82,8 +86,10 @@
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post" onsubmit="Wd()">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>Time setup</h2>
|
||||
Get time from NTP server: <input type="checkbox" name="NT"><br>
|
||||
<input name="NS" maxlength="32"><br>
|
||||
@@ -111,7 +117,10 @@
|
||||
<option value="18">HST (Hawaii)</option>
|
||||
</select><br>
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.
|
||||
Current local time is <span class="times">unknown</span>.<br>
|
||||
Latitude (N): <input name="LT" type="number" min="-66.6" max="66.6" step="0.01">
|
||||
Longitude (E): <input name="LN" type="number" min="-180" max="180" step="0.01">
|
||||
<div id="sun" class="times"></div>
|
||||
<h3>Clock</h3>
|
||||
Clock Overlay:
|
||||
<select name="OL" onchange="Cs()">
|
||||
@@ -133,8 +142,8 @@
|
||||
</div>
|
||||
Countdown Mode: <input type="checkbox" name="CE"><br>
|
||||
Countdown Goal:<br>
|
||||
Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
|
||||
Hour: <input name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" type="number" min="0" max="59" required> Second: <input name="CS" type="number" min="0" max="59" required><br>
|
||||
Year: 20 <input name="CY" class="small" type="number" min="0" max="99" required> Month: <input name="CI" class="small" type="number" min="1" max="12" required> Day: <input name="CD" class="small" type="number" min="1" max="31" required><br>
|
||||
Hour: <input name="CH" class="small" type="number" min="0" max="23" required> Minute: <input name="CM" class="small" type="number" min="0" max="59" required> Second: <input name="CS" class="small" type="number" min="0" max="59" required><br>
|
||||
<h3>Macro presets</h3>
|
||||
<b>Macros have moved!</b><br>
|
||||
<i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="utf-8">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=500">
|
||||
<title>UI Settings</title>
|
||||
<script>
|
||||
@@ -10,16 +10,17 @@
|
||||
var sett = null;
|
||||
var l = {
|
||||
"comp":{
|
||||
"labels":"Show button labels",
|
||||
"colors":{
|
||||
"LABEL":"Color selection methods",
|
||||
"picker": "Color Wheel",
|
||||
"rgb": "RGB sliders",
|
||||
"quick": "Quick color selectors",
|
||||
"hex": "HEX color input"
|
||||
},
|
||||
"pcmbot": "Show bottom tab bar in PC mode",
|
||||
"pid": "Show preset IDs"
|
||||
"labels":"Show button labels",
|
||||
"colors":{
|
||||
"LABEL":"Color selection methods",
|
||||
"picker": "Color Wheel",
|
||||
"rgb": "RGB sliders",
|
||||
"quick": "Quick color selectors",
|
||||
"hex": "HEX color input"
|
||||
},
|
||||
"pcmbot": "Show bottom tab bar in PC mode",
|
||||
"pid": "Show preset IDs",
|
||||
"seglen": "Use LED Count instead of Stop LED on segments"
|
||||
},
|
||||
"theme":{
|
||||
"alpha": {
|
||||
@@ -34,7 +35,6 @@
|
||||
"bg":"BG HEX color"
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
function gId(s)
|
||||
{
|
||||
@@ -52,7 +52,6 @@
|
||||
if( !tar[elem] ) tar[elem] = {}
|
||||
tar = tar[elem];
|
||||
}
|
||||
|
||||
tar[pList[len-1]] = val;
|
||||
}
|
||||
|
||||
@@ -192,7 +191,7 @@
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div style="position:sticky;top:0;background-color:#222;">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="Save()">Save</button><br>
|
||||
<span id="lssuc" style="color:green; display:none">✔ Local UI settings saved!</span>
|
||||
@@ -200,7 +199,7 @@
|
||||
</div>
|
||||
<h2>Web Setup</h2>
|
||||
Server description: <input name="DS" maxlength="32"><br>
|
||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
||||
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
|
||||
You will need to set them again if using a different browser, device or WLED IP address.<br>
|
||||
Refresh the main UI to apply changes.</i><br>
|
||||
@@ -209,8 +208,9 @@
|
||||
|
||||
<h3>UI Appearance</h3>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_labels" class="agi cb"><br>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_pcmbot" class="agi cb"><br>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_pid" class="agi cb"><br>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_pcmbot" class="agi cb"><br>
|
||||
<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>
|
||||
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>
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
</head>
|
||||
<body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
|
||||
</div>
|
||||
<h2>WiFi setup</h2>
|
||||
<h3>Connect to existing network</h3>
|
||||
Network name (SSID, empty to not connect): <br><input name="CS" maxlength="32"><br>
|
||||
|
||||
@@ -1,47 +1,77 @@
|
||||
body {
|
||||
font-family: Verdana, sans-serif;
|
||||
text-align: center;
|
||||
background: #222;
|
||||
color: #fff;
|
||||
line-height: 200%;
|
||||
margin: 0;
|
||||
}
|
||||
hr {
|
||||
border-color: #666;
|
||||
}
|
||||
button {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.3ch solid #333;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.helpB {
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
}
|
||||
input {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 4em;
|
||||
}
|
||||
select {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
td {
|
||||
padding: 2px;
|
||||
}
|
||||
.d5 {
|
||||
width: 4.5em !important;
|
||||
}
|
||||
body {
|
||||
font-family: Verdana, sans-serif;
|
||||
text-align: center;
|
||||
background: #222;
|
||||
color: #fff;
|
||||
line-height: 200%;
|
||||
margin: 0;
|
||||
}
|
||||
hr {
|
||||
border-color: #666;
|
||||
}
|
||||
button {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.3ch solid #333;
|
||||
border-radius: 24px;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 12px 8px 8px;
|
||||
padding: 8px 12px;
|
||||
min-width: 48px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.toprow {
|
||||
top: 0;
|
||||
position: sticky;
|
||||
background-color:#222;
|
||||
z-index:1;
|
||||
}
|
||||
.helpB {
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
}
|
||||
input {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 4em;
|
||||
font-size: medium;
|
||||
margin: 2px;
|
||||
}
|
||||
input[type="number"].big {
|
||||
width: 80px;
|
||||
}
|
||||
input[type="number"].small {
|
||||
width: 40px;
|
||||
}
|
||||
select {
|
||||
margin: 2px;
|
||||
font-size: medium;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
/* Double-sized Checkboxes */
|
||||
-ms-transform: scale(2); /* IE */
|
||||
-moz-transform: scale(2); /* FF */
|
||||
-webkit-transform: scale(2); /* Safari and Chrome */
|
||||
-o-transform: scale(2); /* Opera */
|
||||
transform: scale(2);
|
||||
margin-right: 10px;
|
||||
}
|
||||
select {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
td {
|
||||
padding: 2px;
|
||||
}
|
||||
.d5 {
|
||||
width: 4.5em !important;
|
||||
}
|
||||
|
||||
@@ -98,10 +98,10 @@ void handleIR();
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it);
|
||||
bool deserializeState(JsonObject root);
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true, uint8_t versionAPI = 1);
|
||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true);
|
||||
void serializeInfo(JsonObject root);
|
||||
void serveJson(AsyncWebServerRequest* request);
|
||||
void serveJson(AsyncWebServerRequest* request, uint8_t versionAPI = 1);
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||
|
||||
//led.cpp
|
||||
@@ -135,6 +135,7 @@ bool checkCountdown();
|
||||
void setCountdown();
|
||||
byte weekdayMondayFirst();
|
||||
void checkTimers();
|
||||
void calculateSunriseAndSunset();
|
||||
|
||||
//overlay.cpp
|
||||
void initCronixie();
|
||||
@@ -149,6 +150,7 @@ void _overlayCronixie();
|
||||
void _drawOverlayCronixie();
|
||||
|
||||
//playlist.cpp
|
||||
void shufflePlaylist();
|
||||
void unloadPlaylist();
|
||||
void loadPlaylist(JsonObject playlistObject);
|
||||
void handlePlaylist();
|
||||
|
||||
@@ -382,7 +382,7 @@ String getContentType(AsyncWebServerRequest* request, String filename){
|
||||
if(request->hasArg("download")) return "application/octet-stream";
|
||||
else if(filename.endsWith(".htm")) return "text/html";
|
||||
else if(filename.endsWith(".html")) return "text/html";
|
||||
// else if(filename.endsWith(".css")) return "text/css";
|
||||
else if(filename.endsWith(".css")) return "text/css";
|
||||
// else if(filename.endsWith(".js")) return "application/javascript";
|
||||
else if(filename.endsWith(".json")) return "application/json";
|
||||
else if(filename.endsWith(".png")) return "image/png";
|
||||
|
||||
@@ -42,7 +42,7 @@ function B(){window.history.back()}function U(){document.getElementById("uf").st
|
||||
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}#msg{display:none}
|
||||
</style></head><body><h2>WLED Software Update</h2><form method="POST"
|
||||
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
||||
Installed version: 0.12.0-b5<br>Download the latest binary: <a
|
||||
Installed version: 0.12.0<br>Download the latest binary: <a
|
||||
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
|
||||
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
|
||||
</a><br><input type="file" class="bt" name="update" accept=".bin" required><br>
|
||||
@@ -85,7 +85,7 @@ charset="utf-8"><meta name="theme-color" content="#222222"><title>
|
||||
WLED Live Preview</title><style>
|
||||
body{margin:0}#canv{background:#000;filter:brightness(175%);width:100%;height:100%;position:absolute}
|
||||
</style></head><body><div id="canv"><script>
|
||||
console.info("Live-Preview websocket opening");var socket=new WebSocket("ws://"+document.location.host+"/ws");function updatePreview(e){var o="linear-gradient(90deg,",n=e.length;for(i=0;i<n;i++){var t=e[i];t.length>6&&(t=t.substring(2)),o+="#"+t,i<n-1&&(o+=",")}o+=")",document.getElementById("canv").style.background=o}socket.onopen=function(){console.info("Live-Preview websocket is opened"),socket.send("{'lv':true}")},socket.onclose=function(){console.info("Live-Preview websocket is closing")},socket.onerror=function(e){console.error("Live-Preview websocket error:",e)},socket.onmessage=function(e){try{var o=JSON.parse(e.data);o&&o.leds&&requestAnimationFrame((function(){updatePreview(o.leds)}))}catch(e){console.error("Live-Preview websocket error:",e)}}
|
||||
console.info("Live-Preview websocket opening");var socket=new WebSocket("ws://"+document.location.host+"/ws");function updatePreview(e){var o="linear-gradient(90deg,",n=e.length;for(i=0;i<n;i++){var r=e[i];r.length>6&&(r=r.substring(2)),o+="#"+r,i<n-1&&(o+=",")}o+=")",document.getElementById("canv").style.background=o}socket.onopen=function(){console.info("Live-Preview websocket is opened"),socket.send("{'lv':true,'rev':2}")},socket.onclose=function(){console.info("Live-Preview websocket is closing")},socket.onerror=function(e){console.error("Live-Preview websocket error:",e)},socket.onmessage=function(e){try{var o=JSON.parse(e.data);o&&o.leds&&requestAnimationFrame((function(){updatePreview(o.leds)}))}catch(e){console.error("Live-Preview websocket error:",e)}}
|
||||
</script></body></html>)=====";
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
4189
wled00/html_ui.h
4189
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
||||
hueError = HUE_ERROR_JSON_PARSING; return;
|
||||
}
|
||||
|
||||
int hueErrorCode = root[0][F("error")][F("type")];
|
||||
int hueErrorCode = root[0][F("error")]["type"];
|
||||
if (hueErrorCode)//hue bridge returned error
|
||||
{
|
||||
hueError = hueErrorCode;
|
||||
|
||||
@@ -42,7 +42,7 @@ const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t);
|
||||
void incBrightness()
|
||||
{
|
||||
// dumb incremental search is efficient enough for so few items
|
||||
for (int index = 0; index < numBrightnessSteps; ++index)
|
||||
for (uint8_t index = 0; index < numBrightnessSteps; ++index)
|
||||
{
|
||||
if (brightnessSteps[index] > bri)
|
||||
{
|
||||
|
||||
121
wled00/json.cpp
121
wled00/json.cpp
@@ -40,28 +40,37 @@ void deserializeSegment(JsonObject elem, byte it)
|
||||
{
|
||||
int rgbw[] = {0,0,0,0};
|
||||
bool colValid = false;
|
||||
JsonArray colX = colarr[i];
|
||||
if (colX.isNull()) {
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = colarr[i];
|
||||
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) 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];
|
||||
} 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
|
||||
|
||||
byte cp = copyArray(colX, rgbw, 4);
|
||||
if (cp == 1 && rgbw[0] == 0)
|
||||
seg.setColor(i, 0, id);
|
||||
if (colarr[i].is<unsigned long>()) {
|
||||
// unsigned long RGBW
|
||||
uint32_t colX = colarr[i];
|
||||
rgbw[0] = (colX >> 16) & 0xFF;
|
||||
rgbw[1] = (colX >> 8) & 0xFF;
|
||||
rgbw[2] = (colX ) & 0xFF;
|
||||
rgbw[3] = (colX >> 24) & 0xFF;
|
||||
colValid = true;
|
||||
} else {
|
||||
JsonArray colX = colarr[i];
|
||||
if (colX.isNull()) {
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = colarr[i];
|
||||
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) 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];
|
||||
} 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
|
||||
byte cp = copyArray(colX, rgbw, 4);
|
||||
if (cp == 1 && rgbw[0] == 0)
|
||||
seg.setColor(i, 0, id);
|
||||
colValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colValid) continue;
|
||||
@@ -247,7 +256,7 @@ bool deserializeState(JsonObject root)
|
||||
}
|
||||
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive);
|
||||
} else { //set only the segment with the specified ID
|
||||
deserializeSegment(segVar, it);
|
||||
deserializeSegment(segVar, id);
|
||||
}
|
||||
} else {
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
@@ -291,7 +300,7 @@ bool deserializeState(JsonObject root)
|
||||
return stateResponse;
|
||||
}
|
||||
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds, uint8_t versionAPI)
|
||||
{
|
||||
root["id"] = id;
|
||||
if (segmentBounds) {
|
||||
@@ -307,22 +316,33 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
|
||||
JsonArray colarr = root.createNestedArray("col");
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
JsonArray colX = colarr.createNestedArray();
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
if (versionAPI>1) {
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
if (i == 0) {
|
||||
colX.add(col[0]); colX.add(col[1]); colX.add(col[2]); if (strip.isRgbw) colX.add(col[3]);
|
||||
if (id==strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
if (i==0) colarr.add((unsigned long)((col[0]<<16) | (col[1]<<8) | col[2] | (strip.isRgbw?col[3]<<24:0)));
|
||||
else colarr.add((unsigned long)((colSec[0]<<16) | (colSec[1]<<8) | colSec[2] | (strip.isRgbw?colSec[3]<<24:0)));
|
||||
else
|
||||
colarr.add((unsigned long)seg.colors[i]);
|
||||
}
|
||||
} else {
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
JsonArray colX = colarr.createNestedArray();
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
if (i == 0) {
|
||||
colX.add(col[0]); colX.add(col[1]); colX.add(col[2]); if (strip.isRgbw) colX.add(col[3]);
|
||||
} else {
|
||||
colX.add(colSec[0]); colX.add(colSec[1]); colX.add(colSec[2]); if (strip.isRgbw) colX.add(colSec[3]);
|
||||
}
|
||||
} else {
|
||||
colX.add(colSec[0]); colX.add(colSec[1]); colX.add(colSec[2]); if (strip.isRgbw) colX.add(colSec[3]);
|
||||
colX.add((seg.colors[i] >> 16) & 0xFF);
|
||||
colX.add((seg.colors[i] >> 8) & 0xFF);
|
||||
colX.add((seg.colors[i]) & 0xFF);
|
||||
if (strip.isRgbw)
|
||||
colX.add((seg.colors[i] >> 24) & 0xFF);
|
||||
}
|
||||
} else {
|
||||
colX.add((seg.colors[i] >> 16) & 0xFF);
|
||||
colX.add((seg.colors[i] >> 8) & 0xFF);
|
||||
colX.add((seg.colors[i]) & 0xFF);
|
||||
if (strip.isRgbw)
|
||||
colX.add((seg.colors[i] >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +368,6 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
|
||||
root[F("ps")] = currentPreset;
|
||||
root[F("pl")] = (presetCyclingEnabled) ? 0: -1;
|
||||
|
||||
usermods.addToJsonState(root);
|
||||
|
||||
//temporary for preset cycle
|
||||
@@ -378,14 +397,17 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
|
||||
root[F("mainseg")] = strip.getMainSegmentId();
|
||||
|
||||
uint8_t versionAPI = root["rev"] | 1;
|
||||
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
// TODO: add logic to stop at 12 segments if using versionAPI==1 on ESP8266
|
||||
if (sg.isActive())
|
||||
{
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
serializeSegment(seg0, sg, s, forPreset, segmentBounds);
|
||||
serializeSegment(seg0, sg, s, forPreset, segmentBounds, versionAPI);
|
||||
} else if (forPreset && segmentBounds) { //disable segments not part of preset
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
seg0["stop"] = 0;
|
||||
@@ -423,9 +445,15 @@ void serializeInfo(JsonObject root)
|
||||
leds[F("count")] = ledCount;
|
||||
leds[F("rgbw")] = strip.isRgbw;
|
||||
leds[F("wv")] = strip.isRgbw && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed?
|
||||
JsonArray leds_pin = leds.createNestedArray("pin");
|
||||
leds_pin.add(LEDPIN);
|
||||
|
||||
JsonArray leds_pin = leds.createNestedArray("pin");
|
||||
for (uint8_t s=0; s<busses.getNumBusses(); s++) {
|
||||
Bus *bus = busses.getBus(s);
|
||||
uint8_t pins[5];
|
||||
bus->getPins(pins);
|
||||
leds_pin.add(pins[0]); // need to elaborate this for multipin strips
|
||||
}
|
||||
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds[F("fps")] = strip.getFps();
|
||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
@@ -506,7 +534,6 @@ void serializeInfo(JsonObject root)
|
||||
root[F("freeheap")] = ESP.getFreeHeap();
|
||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
|
||||
usermods.addToJsonInfo(root);
|
||||
|
||||
byte os = 0;
|
||||
@@ -706,15 +733,15 @@ void serializeNodes(JsonObject root)
|
||||
}
|
||||
}
|
||||
|
||||
void serveJson(AsyncWebServerRequest* request)
|
||||
void serveJson(AsyncWebServerRequest* request, uint8_t versionAPI)
|
||||
{
|
||||
byte subJson = 0;
|
||||
const String& url = request->url();
|
||||
if (url.indexOf("state") > 0) subJson = 1;
|
||||
else if (url.indexOf("info") > 0) subJson = 2;
|
||||
else if (url.indexOf("si") > 0) subJson = 3;
|
||||
else if (url.indexOf("si") > 0) subJson = 3;
|
||||
else if (url.indexOf("nodes") > 0) subJson = 4;
|
||||
else if (url.indexOf("palx") > 0) subJson = 5;
|
||||
else if (url.indexOf("palx") > 0) subJson = 5;
|
||||
else if (url.indexOf("live") > 0) {
|
||||
serveLiveLeds(request);
|
||||
return;
|
||||
@@ -738,6 +765,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
switch (subJson)
|
||||
{
|
||||
case 1: //state
|
||||
if (versionAPI>1) doc["rev"] = (int)versionAPI;
|
||||
serializeState(doc); break;
|
||||
case 2: //info
|
||||
serializeInfo(doc); break;
|
||||
@@ -747,6 +775,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
serializePalettes(doc, request); break;
|
||||
default: //all
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
if (versionAPI>1) state["rev"] = (int)versionAPI;
|
||||
serializeState(state);
|
||||
JsonObject info = doc.createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
@@ -765,13 +794,13 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
{
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
AsyncWebSocketClient * wsc = nullptr;
|
||||
if (!request) { //not HTTP, use Websockets
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
wsc = ws.client(wsClient);
|
||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t used = ledCount;
|
||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||
|
||||
129
wled00/ntp.cpp
129
wled00/ntp.cpp
@@ -198,6 +198,9 @@ bool checkNTPResponse()
|
||||
setTime(epoch);
|
||||
DEBUG_PRINTLN(epoch);
|
||||
if (countdownTime - now() > 0) countdownOverTriggered = false;
|
||||
// if time changed re-calculate sunrise/sunset
|
||||
updateLocalTime();
|
||||
calculateSunriseAndSunset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -219,9 +222,7 @@ void getTimeString(char* out)
|
||||
if (hr > 11) hr -= 12;
|
||||
if (hr == 0) hr = 12;
|
||||
}
|
||||
sprintf(out,"%i-%i-%i, %i:%s%i:%s%i",year(localTime), month(localTime), day(localTime),
|
||||
hr,(minute(localTime)<10)?"0":"",minute(localTime),
|
||||
(second(localTime)<10)?"0":"",second(localTime));
|
||||
sprintf_P(out,PSTR("%i-%i-%i, %02d:%02d:%02d"),year(localTime), month(localTime), day(localTime), hr, minute(localTime), second(localTime));
|
||||
if (useAMPM)
|
||||
{
|
||||
strcat(out,(hour(localTime) > 11)? " PM":" AM");
|
||||
@@ -264,16 +265,136 @@ void checkTimers()
|
||||
if (lastTimerMinute != minute(localTime)) //only check once a new minute begins
|
||||
{
|
||||
lastTimerMinute = minute(localTime);
|
||||
|
||||
// re-calculate sunrise and sunset just after midnight
|
||||
if (!hour(localTime) && minute(localTime)==1) calculateSunriseAndSunset();
|
||||
|
||||
DEBUG_PRINTF("Local time: %02d:%02d\n", hour(localTime), minute(localTime));
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (timerMacro[i] != 0
|
||||
&& (timerHours[i] == hour(localTime) || timerHours[i] == 24) //if hour is set to 24, activate every hour
|
||||
&& timerMinutes[i] == minute(localTime)
|
||||
&& (timerWeekday[i] & 0x01) //timer is enabled
|
||||
&& timerWeekday[i] >> weekdayMondayFirst() & 0x01) //timer should activate at current day of week
|
||||
&& ((timerWeekday[i] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
|
||||
{
|
||||
applyPreset(timerMacro[i]);
|
||||
}
|
||||
}
|
||||
// sunrise macro
|
||||
if (sunrise) {
|
||||
time_t tmp = sunrise + timerMinutes[8]*60; // NOTE: may not be ok
|
||||
DEBUG_PRINTF("Trigger time: %02d:%02d\n", hour(tmp), minute(tmp));
|
||||
if (timerMacro[8] != 0
|
||||
&& hour(tmp) == hour(localTime)
|
||||
&& minute(tmp) == minute(localTime)
|
||||
&& (timerWeekday[8] & 0x01) //timer is enabled
|
||||
&& ((timerWeekday[8] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
|
||||
{
|
||||
applyPreset(timerMacro[8]);
|
||||
DEBUG_PRINTF("Sunrise macro %d triggered.",timerMacro[8]);
|
||||
}
|
||||
}
|
||||
// sunset macro
|
||||
if (sunset) {
|
||||
time_t tmp = sunset + timerMinutes[9]*60; // NOTE: may not be ok
|
||||
DEBUG_PRINTF("Trigger time: %02d:%02d\n", hour(tmp), minute(tmp));
|
||||
if (timerMacro[9] != 0
|
||||
&& hour(tmp) == hour(localTime)
|
||||
&& minute(tmp) == minute(localTime)
|
||||
&& (timerWeekday[9] & 0x01) //timer is enabled
|
||||
&& ((timerWeekday[9] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
|
||||
{
|
||||
applyPreset(timerMacro[9]);
|
||||
DEBUG_PRINTF("Sunset macro %d triggered.",timerMacro[9]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ZENITH -0.83
|
||||
// get sunrise (or sunset) time (in minutes) for a given day at a given geo location
|
||||
int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunset=false) {
|
||||
//1. first calculate the day of the year
|
||||
float N1 = floor(275 * month / 9);
|
||||
float N2 = floor((month + 9) / 12);
|
||||
float N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3));
|
||||
float N = N1 - (N2 * N3) + day - 30;
|
||||
|
||||
//2. convert the longitude to hour value and calculate an approximate time
|
||||
float lngHour = lon / 15.0;
|
||||
float t = N + (((sunset ? 18 : 6) - lngHour) / 24);
|
||||
|
||||
//3. calculate the Sun's mean anomaly
|
||||
float M = (0.9856 * t) - 3.289;
|
||||
|
||||
//4. calculate the Sun's true longitude
|
||||
float L = fmod(M + (1.916 * sin(DEG_TO_RAD*M)) + (0.020 * sin(2*DEG_TO_RAD*M)) + 282.634, 360.0);
|
||||
|
||||
//5a. calculate the Sun's right ascension
|
||||
float RA = fmod(RAD_TO_DEG*atan(0.91764 * tan(DEG_TO_RAD*L)), 360.0);
|
||||
|
||||
//5b. right ascension value needs to be in the same quadrant as L
|
||||
float Lquadrant = floor( L/90) * 90;
|
||||
float RAquadrant = floor(RA/90) * 90;
|
||||
RA = RA + (Lquadrant - RAquadrant);
|
||||
|
||||
//5c. right ascension value needs to be converted into hours
|
||||
RA /= 15.;
|
||||
|
||||
//6. calculate the Sun's declination
|
||||
float sinDec = 0.39782 * sin(DEG_TO_RAD*L);
|
||||
float cosDec = cos(asin(sinDec));
|
||||
|
||||
//7a. calculate the Sun's local hour angle
|
||||
float cosH = (sin(DEG_TO_RAD*ZENITH) - (sinDec * sin(DEG_TO_RAD*lat))) / (cosDec * cos(DEG_TO_RAD*lat));
|
||||
if (cosH > 1 && !sunset) return 0; // the sun never rises on this location (on the specified date)
|
||||
if (cosH < -1 && sunset) return 0; // the sun never sets on this location (on the specified date)
|
||||
|
||||
//7b. finish calculating H and convert into hours
|
||||
float H = sunset ? RAD_TO_DEG*acos(cosH) : 360 - RAD_TO_DEG*acos(cosH);
|
||||
H /= 15.;
|
||||
|
||||
//8. calculate local mean time of rising/setting
|
||||
float T = H + RA - (0.06571 * t) - 6.622;
|
||||
|
||||
//9. adjust back to UTC
|
||||
float UT = fmod(T - lngHour, 24.0);
|
||||
|
||||
// return in minutes from midnight
|
||||
return UT*60;
|
||||
}
|
||||
|
||||
// calculate sunrise and sunset (if longitude and latitude are set)
|
||||
void calculateSunriseAndSunset() {
|
||||
if ((int)(longitude*10.) || (int)(latitude*10.)) {
|
||||
struct tm tim_0;
|
||||
tim_0.tm_year = year(localTime)-1900;
|
||||
tim_0.tm_mon = month(localTime)-1;
|
||||
tim_0.tm_mday = day(localTime);
|
||||
tim_0.tm_sec = 0;
|
||||
tim_0.tm_isdst = 0;
|
||||
|
||||
int minUTC = getSunriseUTC(year(localTime), month(localTime), day(localTime), latitude, longitude);
|
||||
if (minUTC) {
|
||||
// there is a sunrise
|
||||
tim_0.tm_hour = minUTC / 60;
|
||||
tim_0.tm_min = minUTC % 60;
|
||||
sunrise = tz->toLocal(mktime(&tim_0) - utcOffsetSecs);
|
||||
DEBUG_PRINTF("Sunrise: %02d:%02d\n", hour(sunrise), minute(sunrise));
|
||||
} else {
|
||||
sunrise = 0;
|
||||
}
|
||||
|
||||
minUTC = getSunriseUTC(year(localTime), month(localTime), day(localTime), latitude, longitude, true);
|
||||
if (minUTC) {
|
||||
// there is a sunset
|
||||
tim_0.tm_hour = minUTC / 60;
|
||||
tim_0.tm_min = minUTC % 60;
|
||||
sunset = tz->toLocal(mktime(&tim_0) - utcOffsetSecs);
|
||||
DEBUG_PRINTF("Sunset: %02d:%02d\n", hour(sunset), minute(sunset));
|
||||
} else {
|
||||
sunset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ void _overlayAnalogClock()
|
||||
|
||||
void _overlayAnalogCountdown()
|
||||
{
|
||||
if (now() < countdownTime)
|
||||
if ((unsigned long)now() < countdownTime)
|
||||
{
|
||||
long diff = countdownTime - now();
|
||||
double pval = 60;
|
||||
@@ -369,7 +369,7 @@ void _drawOverlayCronixie()
|
||||
}
|
||||
|
||||
#else // WLED_DISABLE_CRONIXIE
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[]) {}
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[]) {return 0;}
|
||||
void setCronixie() {}
|
||||
void _overlayCronixie() {}
|
||||
void _drawOverlayCronixie() {}
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Methods to handle saving and loading presets to/from the filesystem
|
||||
*/
|
||||
|
||||
bool applyPreset(byte index)
|
||||
{
|
||||
if (index == 0) return false;
|
||||
if (fileDoc) {
|
||||
errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
JsonObject fdo = fileDoc->as<JsonObject>();
|
||||
if (fdo["ps"] == index) fdo.remove("ps"); //remove load request for same presets to prevent recursive crash
|
||||
#ifdef WLED_DEBUG_FS
|
||||
serializeJson(*fileDoc, Serial);
|
||||
#endif
|
||||
deserializeState(fdo);
|
||||
} else {
|
||||
DEBUGFS_PRINTLN(F("Make read buf"));
|
||||
DynamicJsonDocument fDoc(JSON_BUFFER_SIZE);
|
||||
errorFlag = readObjectFromFileUsingId("/presets.json", index, &fDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
JsonObject fdo = fDoc.as<JsonObject>();
|
||||
if (fdo["ps"] == index) fdo.remove("ps");
|
||||
#ifdef WLED_DEBUG_FS
|
||||
serializeJson(fDoc, Serial);
|
||||
#endif
|
||||
deserializeState(fdo);
|
||||
}
|
||||
|
||||
if (!errorFlag) {
|
||||
currentPreset = index;
|
||||
isPreset = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
||||
{
|
||||
if (index == 0 || index > 250) return;
|
||||
bool docAlloc = (fileDoc != nullptr);
|
||||
JsonObject sObj = saveobj;
|
||||
|
||||
if (!docAlloc) {
|
||||
DEBUGFS_PRINTLN(F("Allocating saving buffer"));
|
||||
DynamicJsonDocument lDoc(JSON_BUFFER_SIZE);
|
||||
sObj = lDoc.to<JsonObject>();
|
||||
if (pname) sObj["n"] = pname;
|
||||
DEBUGFS_PRINTLN(F("Save current state"));
|
||||
serializeState(sObj, true);
|
||||
currentPreset = index;
|
||||
|
||||
writeObjectToFileUsingId("/presets.json", index, &lDoc);
|
||||
} else { //from JSON API
|
||||
DEBUGFS_PRINTLN(F("Reuse recv buffer"));
|
||||
sObj.remove(F("psave"));
|
||||
sObj.remove(F("v"));
|
||||
|
||||
if (!sObj["o"]) {
|
||||
DEBUGFS_PRINTLN(F("Save current state"));
|
||||
serializeState(sObj, true, sObj["ib"], sObj["sb"]);
|
||||
currentPreset = index;
|
||||
}
|
||||
sObj.remove("o");
|
||||
sObj.remove("ib");
|
||||
sObj.remove("sb");
|
||||
sObj.remove(F("error"));
|
||||
sObj.remove(F("time"));
|
||||
|
||||
writeObjectToFileUsingId("/presets.json", index, fileDoc);
|
||||
}
|
||||
presetsModifiedTime = now(); //unix time
|
||||
updateFSInfo();
|
||||
}
|
||||
|
||||
void deletePreset(byte index) {
|
||||
StaticJsonDocument<24> empty;
|
||||
writeObjectToFileUsingId("/presets.json", index, &empty);
|
||||
presetsModifiedTime = now(); //unix time
|
||||
updateFSInfo();
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Methods to handle saving and loading presets to/from the filesystem
|
||||
*/
|
||||
|
||||
bool applyPreset(byte index)
|
||||
{
|
||||
if (index == 0) return false;
|
||||
if (fileDoc) { // from POST "/json" handler (wled_server.cpp)
|
||||
errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
JsonObject fdo = fileDoc->as<JsonObject>();
|
||||
if (fdo["ps"] == index) fdo.remove("ps"); //remove load request for same presets to prevent recursive crash
|
||||
#ifdef WLED_DEBUG_FS
|
||||
serializeJson(*fileDoc, Serial);
|
||||
#endif
|
||||
deserializeState(fdo);
|
||||
} else {
|
||||
DEBUGFS_PRINTLN(F("Make read buf"));
|
||||
DynamicJsonDocument fDoc(JSON_BUFFER_SIZE);
|
||||
errorFlag = readObjectFromFileUsingId("/presets.json", index, &fDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
JsonObject fdo = fDoc.as<JsonObject>();
|
||||
if (fdo["ps"] == index) fdo.remove("ps");
|
||||
#ifdef WLED_DEBUG_FS
|
||||
serializeJson(fDoc, Serial);
|
||||
#endif
|
||||
deserializeState(fdo);
|
||||
}
|
||||
|
||||
if (!errorFlag) {
|
||||
currentPreset = index;
|
||||
isPreset = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
||||
{
|
||||
if (index == 0 || index > 250) return;
|
||||
bool docAlloc = (fileDoc != nullptr);
|
||||
JsonObject sObj = saveobj;
|
||||
|
||||
if (!docAlloc) {
|
||||
DEBUGFS_PRINTLN(F("Allocating saving buffer"));
|
||||
DynamicJsonDocument lDoc(JSON_BUFFER_SIZE);
|
||||
sObj = lDoc.to<JsonObject>();
|
||||
if (pname) sObj["n"] = pname;
|
||||
DEBUGFS_PRINTLN(F("Save current state"));
|
||||
serializeState(sObj, true);
|
||||
currentPreset = index;
|
||||
|
||||
writeObjectToFileUsingId("/presets.json", index, &lDoc);
|
||||
} else { //from JSON API
|
||||
DEBUGFS_PRINTLN(F("Reuse recv buffer"));
|
||||
sObj.remove(F("psave"));
|
||||
sObj.remove(F("v"));
|
||||
|
||||
if (!sObj["o"]) {
|
||||
DEBUGFS_PRINTLN(F("Save current state"));
|
||||
serializeState(sObj, true, sObj["ib"], sObj["sb"]);
|
||||
currentPreset = index;
|
||||
}
|
||||
sObj.remove("o");
|
||||
sObj.remove("ib");
|
||||
sObj.remove("sb");
|
||||
sObj.remove(F("error"));
|
||||
sObj.remove(F("time"));
|
||||
|
||||
writeObjectToFileUsingId("/presets.json", index, fileDoc);
|
||||
}
|
||||
presetsModifiedTime = now(); //unix time
|
||||
updateFSInfo();
|
||||
}
|
||||
|
||||
void deletePreset(byte index) {
|
||||
StaticJsonDocument<24> empty;
|
||||
writeObjectToFileUsingId("/presets.json", index, &empty);
|
||||
presetsModifiedTime = now(); //unix time
|
||||
updateFSInfo();
|
||||
}
|
||||
@@ -82,9 +82,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
if (irPin>=0 && pinManager.isPinAllocated(irPin)) pinManager.deallocatePin(irPin);
|
||||
#endif
|
||||
if (btnPin>=0 && pinManager.isPinAllocated(btnPin)) pinManager.deallocatePin(btnPin);
|
||||
//TODO remove all busses, but not in this system call
|
||||
//busses->removeAll();
|
||||
|
||||
strip.isRgbw = false;
|
||||
|
||||
uint8_t skip = request->hasArg(F("SL")) ? LED_SKIP_AMOUNT : 0;
|
||||
uint8_t colorOrder, type;
|
||||
uint16_t length, start;
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
@@ -96,8 +97,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type
|
||||
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
|
||||
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
|
||||
char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||
if (!request->hasArg(lp)) {
|
||||
DEBUG_PRINTLN("No data."); break;
|
||||
DEBUG_PRINTLN(F("No data.")); break;
|
||||
}
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
lp[1] = 48+i;
|
||||
@@ -105,32 +107,29 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
|
||||
}
|
||||
type = request->arg(lt).toInt();
|
||||
//if (isRgbw(type)) strip.isRgbw = true; //30fps
|
||||
//strip.isRgbw = true;
|
||||
|
||||
if (request->hasArg(ew)) SET_BIT(type,7); else UNSET_BIT(type,7); // hack bit 7 to indicate RGBW (as a LED type override if necessary)
|
||||
strip.isRgbw = strip.isRgbw || request->hasArg(ew);
|
||||
|
||||
colorOrder = request->arg(co).toInt();
|
||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
|
||||
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
|
||||
length = request->arg(lc).toInt();
|
||||
t += length = request->arg(lc).toInt();
|
||||
} else {
|
||||
break; // no parameter
|
||||
}
|
||||
|
||||
colorOrder = request->arg(co).toInt();
|
||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : 0;
|
||||
|
||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv));
|
||||
//if (BusManager::isRgbw(type)) strip.isRgbw = true; //20fps
|
||||
//strip.isRgbw = true;
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skip);
|
||||
doInitBusses = true;
|
||||
}
|
||||
|
||||
ledCount = request->arg(F("LC")).toInt();
|
||||
if (t > 0 && t <= MAX_LEDS) ledCount = t;
|
||||
|
||||
// upate other pins
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
int hw_ir_pin = request->arg(F("IR")).toInt();
|
||||
if (pinManager.isPinOk(hw_ir_pin) && pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
if (pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
irPin = hw_ir_pin;
|
||||
} else {
|
||||
irPin = -1;
|
||||
@@ -153,13 +152,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
btnPin = -1;
|
||||
}
|
||||
|
||||
int hw_aux_pin = request->arg(F("AX")).toInt();
|
||||
if (pinManager.allocatePin(hw_aux_pin,true)) {
|
||||
auxPin = hw_aux_pin;
|
||||
} else {
|
||||
auxPin = -1;
|
||||
}
|
||||
|
||||
strip.ablMilliampsMax = request->arg(F("MA")).toInt();
|
||||
strip.milliampsPerLed = request->arg(F("LA")).toInt();
|
||||
|
||||
@@ -188,7 +180,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
t = request->arg(F("PB")).toInt();
|
||||
if (t >= 0 && t < 4) strip.paletteBlend = t;
|
||||
skipFirstLed = request->hasArg(F("SL"));
|
||||
t = request->arg(F("BF")).toInt();
|
||||
if (t > 0) briMultiplier = t;
|
||||
}
|
||||
@@ -299,6 +290,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
//start ntp if not already connected
|
||||
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
|
||||
|
||||
longitude = request->arg(F("LN")).toFloat();
|
||||
latitude = request->arg(F("LT")).toFloat();
|
||||
// force a sunrise/sunset re-calculation
|
||||
calculateSunriseAndSunset();
|
||||
|
||||
if (request->hasArg(F("OL"))) {
|
||||
overlayDefault = request->arg(F("OL")).toInt();
|
||||
overlayCurrent = overlayDefault;
|
||||
@@ -330,7 +326,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
macroDoublePress = request->arg(F("MD")).toInt();
|
||||
|
||||
char k[3]; k[2] = 0;
|
||||
for (int i = 0; i<8; i++)
|
||||
for (int i = 0; i<10; i++)
|
||||
{
|
||||
k[1] = i+48;//ascii 0,1,2,3
|
||||
|
||||
@@ -722,16 +718,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
|
||||
|
||||
//toggle general purpose output
|
||||
if (auxPin>=0) {
|
||||
pos = req.indexOf(F("AX="));
|
||||
if (pos > 0) {
|
||||
auxTime = getNumVal(&req, pos);
|
||||
auxActive = true;
|
||||
if (auxTime == 0) auxActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
pos = req.indexOf(F("TT="));
|
||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||
|
||||
|
||||
@@ -83,6 +83,10 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
|
||||
realtimeTimeout = millis() + timeoutMs;
|
||||
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
|
||||
// if strip is off (bri==0) and not already in RTM
|
||||
if (bri == 0 && !realtimeMode) {
|
||||
strip.setBrightness(scaledBri(briLast));
|
||||
}
|
||||
realtimeMode = md;
|
||||
|
||||
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(scaledBri(255));
|
||||
|
||||
@@ -227,34 +227,39 @@ void WLED::loop()
|
||||
#ifdef ESP8266
|
||||
MDNS.update();
|
||||
#endif
|
||||
|
||||
//millis() rolls over every 50 days
|
||||
if (lastMqttReconnectAttempt > millis()) {
|
||||
rolloverMillis++;
|
||||
lastMqttReconnectAttempt = 0;
|
||||
}
|
||||
if (millis() - lastMqttReconnectAttempt > 30000) {
|
||||
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
|
||||
// lastMqttReconnectAttempt = millis(); // don't do it in initMqtt()
|
||||
initMqtt();
|
||||
yield();
|
||||
// refresh WLED nodes list
|
||||
refreshNodeList();
|
||||
if (nodeBroadcastEnabled) sendSysInfoUDP();
|
||||
yield();
|
||||
}
|
||||
|
||||
//LED settings have been saved, re-init busses
|
||||
//This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate!
|
||||
if (doInitBusses) {
|
||||
doInitBusses = false;
|
||||
DEBUG_PRINTLN(F("Re-init busses."));
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
strip.isRgbw = false;
|
||||
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
|
||||
if (busConfigs[i] == nullptr) break;
|
||||
mem += busses.memUsage(*busConfigs[i]);
|
||||
mem += BusManager::memUsage(*busConfigs[i]);
|
||||
if (mem <= MAX_LED_MEMORY) busses.add(*busConfigs[i]);
|
||||
//if (BusManager::isRgbw(busConfigs[i]->type)) strip.isRgbw = true;
|
||||
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(busConfigs[i]->type));
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
}
|
||||
strip.finalizeInit(ledCount, skipFirstLed);
|
||||
strip.finalizeInit();
|
||||
yield();
|
||||
serializeConfig();
|
||||
}
|
||||
|
||||
|
||||
yield();
|
||||
handleWs();
|
||||
handleStatusLED();
|
||||
@@ -307,9 +312,15 @@ void WLED::setup()
|
||||
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
|
||||
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
|
||||
|
||||
#ifdef WLED_USE_DMX //reserve GPIO2 as hardcoded DMX pin
|
||||
pinManager.allocatePin(2);
|
||||
#ifdef WLED_DEBUG
|
||||
pinManager.allocatePin(1,true); // GPIO1 reserved for debug output
|
||||
#endif
|
||||
#ifdef WLED_USE_DMX //reserve GPIO2 as hardcoded DMX pin
|
||||
pinManager.allocatePin(2,false);
|
||||
#endif
|
||||
//#ifdef WLED_ENABLE_ADALIGHT // reserve GPIO3 (RX) pin for ADALight
|
||||
// pinManager.allocatePin(3,false);
|
||||
//#endif
|
||||
|
||||
bool fsinit = false;
|
||||
DEBUGFS_PRINTLN(F("Mount FS"));
|
||||
@@ -323,6 +334,8 @@ void WLED::setup()
|
||||
errorFlag = ERR_FS_BEGIN;
|
||||
} else deEEP();
|
||||
updateFSInfo();
|
||||
|
||||
DEBUG_PRINTLN(F("Reading config"));
|
||||
deserializeConfig();
|
||||
|
||||
#if STATUSLED
|
||||
@@ -339,7 +352,10 @@ void WLED::setup()
|
||||
|
||||
//DEBUG_PRINTLN(F("Load EEPROM"));
|
||||
//loadSettingsFromEEPROM();
|
||||
DEBUG_PRINTLN(F("Initializing strip"));
|
||||
beginStrip();
|
||||
|
||||
DEBUG_PRINTLN(F("Usermods setup"));
|
||||
userSetup();
|
||||
usermods.setup();
|
||||
if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0)
|
||||
@@ -349,7 +365,14 @@ void WLED::setup()
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
#endif
|
||||
|
||||
Serial.println(F("Ada"));
|
||||
#ifdef WLED_ENABLE_ADALIGHT // reserve GPIO3 (RX) pin for ADALight
|
||||
if (!pinManager.isPinAllocated(3)) {
|
||||
Serial.println(F("Ada"));
|
||||
pinManager.allocatePin(3,false);
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("ADALight disabled due to GPIO3 being used."));
|
||||
}
|
||||
#endif
|
||||
|
||||
// generate module IDs
|
||||
escapedMac = WiFi.macAddress();
|
||||
@@ -393,16 +416,14 @@ void WLED::setup()
|
||||
void WLED::beginStrip()
|
||||
{
|
||||
// Initialize NeoPixel Strip and button
|
||||
|
||||
if (ledCount > MAX_LEDS || ledCount == 0)
|
||||
ledCount = 30;
|
||||
|
||||
strip.finalizeInit(ledCount, skipFirstLed);
|
||||
strip.finalizeInit(); // busses created during deserializeConfig()
|
||||
strip.populateDefaultSegments();
|
||||
strip.setBrightness(0);
|
||||
strip.setShowCallback(handleOverlayDraw);
|
||||
|
||||
if (bootPreset > 0) applyPreset(bootPreset);
|
||||
if (turnOnAtBoot) {
|
||||
if (bootPreset > 0) {
|
||||
applyPreset(bootPreset);
|
||||
} else if (turnOnAtBoot) {
|
||||
if (briS > 0) bri = briS;
|
||||
else if (bri == 0) bri = 128;
|
||||
} else {
|
||||
@@ -411,12 +432,10 @@ void WLED::beginStrip()
|
||||
colorUpdated(NOTIFIER_CALL_MODE_INIT);
|
||||
|
||||
// init relay pin
|
||||
if (rlyPin>=0)
|
||||
digitalWrite(rlyPin, (rlyMde ? bri : !bri));
|
||||
if (rlyPin>=0) digitalWrite(rlyPin, (bri ? rlyMde : !rlyMde));
|
||||
|
||||
// disable button if it is "pressed" unintentionally
|
||||
if (btnPin>=0 && isButtonPressed())
|
||||
buttonEnabled = false;
|
||||
if (btnPin>=0 && isButtonPressed()) buttonEnabled = false;
|
||||
}
|
||||
|
||||
void WLED::initAP(bool resetAP)
|
||||
@@ -594,7 +613,7 @@ void WLED::handleConnection()
|
||||
// reconnect WiFi to clear stale allocations if heap gets too low
|
||||
if (millis() - heapTime > 5000) {
|
||||
uint32_t heap = ESP.getFreeHeap();
|
||||
if (heap < 9000 && lastHeap < 9000) {
|
||||
if (heap < JSON_BUFFER_SIZE+512 && lastHeap < JSON_BUFFER_SIZE+512) {
|
||||
DEBUG_PRINT(F("Heap too low! "));
|
||||
DEBUG_PRINTLN(heap);
|
||||
forceReconnect = true;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2103300
|
||||
#define VERSION 2104031
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@@ -16,8 +16,8 @@
|
||||
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
||||
|
||||
// ESP8266-01 (black) has 1MB flash and can thus fit the whole program, although OTA update is not possible. Use 1M(128K SPIFFS).
|
||||
// Uncomment some of the following lines to disable features to compile for ESP8266-01 (max flash size 434kB):
|
||||
// Alternatively, with platformio pass your chosen flags to your custom build target in platformio.ini.override
|
||||
// Uncomment some of the following lines to disable features:
|
||||
// Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini
|
||||
|
||||
// You are required to disable over-the-air updates:
|
||||
//#define WLED_DISABLE_OTA // saves 14kb
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
#define WLED_ENABLE_MQTT // saves 12kb
|
||||
#endif
|
||||
#define WLED_ENABLE_ADALIGHT // saves 500b only
|
||||
//#define WLED_ENABLE_ADALIGHT // saves 500b only (uses GPIO3 (RX) for serial)
|
||||
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
||||
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||
#ifndef WLED_DISABLE_WEBSOCKETS
|
||||
@@ -168,7 +168,7 @@
|
||||
#endif
|
||||
|
||||
// Global Variable definitions
|
||||
WLED_GLOBAL char versionString[] _INIT("0.12.0-b5");
|
||||
WLED_GLOBAL char versionString[] _INIT("0.12.0");
|
||||
#define WLED_CODENAME "Hikari"
|
||||
|
||||
// AP and OTA default passwords (for maximum security change them!)
|
||||
@@ -238,7 +238,6 @@ WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for ava
|
||||
WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading color transition
|
||||
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // default crossfade duration in ms
|
||||
|
||||
WLED_GLOBAL bool skipFirstLed _INIT(false); // ignore first LED in strip (useful if you need the LED as signal repeater)
|
||||
WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127)
|
||||
|
||||
// User Interface CONFIG
|
||||
@@ -448,10 +447,10 @@ WLED_GLOBAL bool countdownOverTriggered _INIT(true);
|
||||
|
||||
// timer
|
||||
WLED_GLOBAL byte lastTimerMinute _INIT(0);
|
||||
WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL byte timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255 })); // weekdays to activate on
|
||||
WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 })); // weekdays to activate on
|
||||
// bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity
|
||||
|
||||
// blynk
|
||||
@@ -481,19 +480,6 @@ WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0);
|
||||
WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT);
|
||||
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
|
||||
|
||||
// auxiliary debug pin
|
||||
#ifndef AUXPIN
|
||||
WLED_GLOBAL int8_t auxPin _INIT(-1);
|
||||
#else
|
||||
WLED_GLOBAL int8_t auxPin _INIT(AUXPIN);
|
||||
#endif
|
||||
WLED_GLOBAL byte auxTime _INIT(0);
|
||||
WLED_GLOBAL unsigned long auxStartTime _INIT(0);
|
||||
WLED_GLOBAL bool auxActive _INIT(false);
|
||||
WLED_GLOBAL bool auxActiveBefore _INIT(false);
|
||||
WLED_GLOBAL byte auxDefaultState _INIT(0); // 0: input 1: high 2: low
|
||||
WLED_GLOBAL byte auxTriggeredState _INIT(0); // 0: input 1: high 2: low
|
||||
|
||||
// alexa udp
|
||||
WLED_GLOBAL String escapedMac;
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
@@ -512,6 +498,10 @@ WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
|
||||
WLED_GLOBAL IPAddress ntpServerIP;
|
||||
WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390);
|
||||
WLED_GLOBAL uint16_t rolloverMillis _INIT(0);
|
||||
WLED_GLOBAL float longitude _INIT(0.0);
|
||||
WLED_GLOBAL float latitude _INIT(0.0);
|
||||
WLED_GLOBAL time_t sunrise _INIT(0);
|
||||
WLED_GLOBAL time_t sunset _INIT(0);
|
||||
|
||||
// Temp buffer
|
||||
WLED_GLOBAL char* obuf;
|
||||
@@ -577,7 +567,7 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
#else
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#define DEBUG_PRINTF(x)
|
||||
#define DEBUG_PRINTF(x...)
|
||||
#endif
|
||||
|
||||
#ifdef WLED_DEBUG_FS
|
||||
|
||||
@@ -237,7 +237,7 @@ void loadSettingsFromEEPROM()
|
||||
|
||||
if (lastEEPROMversion > 9)
|
||||
{
|
||||
strip.setColorOrder(EEPROM.read(383));
|
||||
//strip.setColorOrder(EEPROM.read(383));
|
||||
irEnabled = EEPROM.read(385);
|
||||
strip.ablMilliampsMax = EEPROM.read(387) + ((EEPROM.read(388) << 8) & 0xFF00);
|
||||
} else if (lastEEPROMversion > 1) //ABL is off by default when updating from version older than 0.8.2
|
||||
@@ -317,7 +317,7 @@ void loadSettingsFromEEPROM()
|
||||
notifyMacro = EEPROM.read(2201);
|
||||
|
||||
strip.rgbwMode = EEPROM.read(2203);
|
||||
skipFirstLed = EEPROM.read(2204);
|
||||
//was skipFirstLed = EEPROM.read(2204);
|
||||
|
||||
if (EEPROM.read(2210) || EEPROM.read(2211) || EEPROM.read(2212))
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ void handleSerial()
|
||||
if (!realtimeOverride) setRealtimePixel(pixel++, red, green, blue, 0);
|
||||
if (--count > 0) state = AdaState::Data_Red;
|
||||
else {
|
||||
if (!realtimeMode && bri == 0) strip.setBrightness(briLast);
|
||||
// if (!realtimeMode && bri == 0) strip.setBrightness(briLast); //realtimeLock() handles turning strip on/off
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
|
||||
|
||||
if (!realtimeOverride) strip.show();
|
||||
|
||||
@@ -84,6 +84,7 @@ void initServer()
|
||||
|
||||
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/json", [](AsyncWebServerRequest *request) {
|
||||
bool verboseResponse = false;
|
||||
uint8_t vAPI = 1;
|
||||
{ //scope JsonDocument so it releases its buffer
|
||||
DynamicJsonDocument jsonBuffer(JSON_BUFFER_SIZE);
|
||||
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject));
|
||||
@@ -91,12 +92,16 @@ void initServer()
|
||||
if (error || root.isNull()) {
|
||||
request->send(400, "application/json", F("{\"error\":9}")); return;
|
||||
}
|
||||
fileDoc = &jsonBuffer;
|
||||
if (root.containsKey("rev"))
|
||||
{
|
||||
vAPI = root["rev"] | 1;
|
||||
}
|
||||
fileDoc = &jsonBuffer; // used for applying presets (presets.cpp)
|
||||
verboseResponse = deserializeState(root);
|
||||
fileDoc = nullptr;
|
||||
}
|
||||
if (verboseResponse) { //if JSON contains "v"
|
||||
serveJson(request); return;
|
||||
serveJson(request,vAPI); return;
|
||||
}
|
||||
request->send(200, "application/json", F("{\"success\":true}"));
|
||||
});
|
||||
@@ -186,15 +191,15 @@ void initServer()
|
||||
}
|
||||
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
server.on("/dmxmap", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send_P(200, "text/html", PAGE_dmxmap , dmxProcessor);
|
||||
});
|
||||
#else
|
||||
server.on("/dmxmap", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 501, "Not implemented", F("DMX support is not enabled in this build."), 254);
|
||||
});
|
||||
#endif
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
server.on("/dmxmap", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send_P(200, "text/html", PAGE_dmxmap , dmxProcessor);
|
||||
});
|
||||
#else
|
||||
server.on("/dmxmap", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 501, "Not implemented", F("DMX support is not enabled in this build."), 254);
|
||||
});
|
||||
#endif
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (captivePortal(request)) return;
|
||||
serveIndexOrWelcome(request);
|
||||
@@ -247,7 +252,11 @@ bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
|
||||
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
|
||||
{
|
||||
response->addHeader(F("Cache-Control"),"no-cache");
|
||||
#ifndef WLED_DEBUG
|
||||
response->addHeader(F("Cache-Control"),"max-age=604800"); // 7 day caching
|
||||
#else
|
||||
response->addHeader(F("Cache-Control"),"no-store,max-age=0"); // prevent caching if debug build
|
||||
#endif
|
||||
response->addHeader(F("ETag"), String(VERSION));
|
||||
}
|
||||
|
||||
@@ -261,7 +270,6 @@ void serveIndex(AsyncWebServerRequest* request)
|
||||
|
||||
response->addHeader(F("Content-Encoding"),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
uint16_t wsLiveClientId = 0;
|
||||
unsigned long wsLastLiveTime = 0;
|
||||
//uint8_t* wsFrameBuffer = nullptr;
|
||||
uint8_t vAPI = 2;
|
||||
struct client_api {
|
||||
uint32_t c = 0;
|
||||
uint8_t vAPI = 1;
|
||||
} ClientApis[DEFAULT_MAX_WS_CLIENTS];
|
||||
|
||||
#define WS_LIVE_INTERVAL 40
|
||||
|
||||
@@ -15,11 +20,25 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
{
|
||||
if(type == WS_EVT_CONNECT){
|
||||
//client connected
|
||||
for (uint8_t i=0; i<DEFAULT_MAX_WS_CLIENTS; i++) {
|
||||
if (ClientApis[i].c) continue; // used slot
|
||||
ClientApis[i].c = client->id();
|
||||
ClientApis[i].vAPI = 1;
|
||||
DEBUG_PRINTF("New WS client [%d]: %d\n", (int)i, client->id());
|
||||
break;
|
||||
}
|
||||
sendDataWs(client);
|
||||
//client->ping();
|
||||
} else if(type == WS_EVT_DISCONNECT){
|
||||
//client disconnected
|
||||
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
||||
for (uint8_t i=0; i<DEFAULT_MAX_WS_CLIENTS; i++) {
|
||||
if (ClientApis[i].c != client->id()) continue;
|
||||
ClientApis[i].c = 0; // clear slot
|
||||
ClientApis[i].vAPI = 1;
|
||||
DEBUG_PRINTF("Removed WS client [%d]: %d\n", (int)i, client->id());
|
||||
break;
|
||||
}
|
||||
} else if(type == WS_EVT_DATA){
|
||||
//data packet
|
||||
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||
@@ -38,7 +57,15 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
{
|
||||
wsLiveClientId = root["lv"] ? client->id() : 0;
|
||||
}
|
||||
|
||||
if (root.containsKey("rev"))
|
||||
{
|
||||
for (uint8_t i=0; i<DEFAULT_MAX_WS_CLIENTS; i++) {
|
||||
if (ClientApis[i].c != client->id()) continue;
|
||||
ClientApis[i].vAPI = root["rev"];
|
||||
DEBUG_PRINTF("API for WS client [%d]: %d\n", (int)i, (int)ClientApis[i].vAPI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
verboseResponse = deserializeState(root);
|
||||
}
|
||||
if (verboseResponse || millis() - lastInterfaceUpdate < 1900) sendDataWs(client); //update if it takes longer than 100ms until next "broadcast"
|
||||
@@ -79,6 +106,21 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
{ //scope JsonDocument so it releases its buffer
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
if (client) {
|
||||
for (uint8_t i=0; i<DEFAULT_MAX_WS_CLIENTS; i++) {
|
||||
if (ClientApis[i].c != client->id()) continue;
|
||||
state["rev"] = ClientApis[i].vAPI;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
uint8_t minAPI = 2;
|
||||
for (uint8_t i=0; i<DEFAULT_MAX_WS_CLIENTS; i++) {
|
||||
if (!ClientApis[i].c) continue;
|
||||
if (minAPI > ClientApis[i].vAPI) minAPI = ClientApis[i].vAPI;
|
||||
}
|
||||
state["rev"] = minAPI;
|
||||
}
|
||||
DEBUG_PRINTF("Actual API used: %d\n", (int)state["rev"]);
|
||||
serializeState(state);
|
||||
JsonObject info = doc.createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "wled.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Sending XML status files to client
|
||||
@@ -187,7 +188,8 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
if (subPage <1 || subPage >7) return;
|
||||
|
||||
if (subPage == 1) {
|
||||
if (subPage == 1)
|
||||
{
|
||||
sappends('s',SET_F("CS"),clientSSID);
|
||||
|
||||
byte l = strlen(clientPass);
|
||||
@@ -253,25 +255,63 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
}
|
||||
|
||||
if (subPage == 2) {
|
||||
if (subPage == 2)
|
||||
{
|
||||
char nS[8];
|
||||
|
||||
// add usermod pins as d.um_p array (TODO: usermod config shouldn't use state. instead we should load "um" object from cfg.json)
|
||||
/*DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
JsonObject mods = doc.createNestedObject(F("mods"));
|
||||
usermods.addToJsonState(mods);
|
||||
// (TODO: usermod config shouldn't use state. instead we should load "um" object from cfg.json)
|
||||
// add reserved and usermod pins as d.um_p array
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
||||
JsonObject mods = doc.createNestedObject(F("um"));
|
||||
usermods.addToConfig(mods);
|
||||
oappend(SET_F("d.um_p=["));
|
||||
if (!mods.isNull()) {
|
||||
uint8_t i=0;
|
||||
oappend(SET_F("d.um_p=["));
|
||||
for (JsonPair kv : mods) {
|
||||
if (strncmp_P(kv.key().c_str(),PSTR("pin_"),4) == 0) {
|
||||
if (i++) oappend(SET_F(","));
|
||||
oappend(itoa((int)kv.value(),nS,10));
|
||||
oappendi((int)kv.value());
|
||||
} else if (!kv.value().isNull()) {
|
||||
// element is an JsonObject
|
||||
JsonObject obj = kv.value();
|
||||
if (obj[F("pin")] != nullptr) {
|
||||
if (i++) oappend(SET_F(","));
|
||||
oappendi((int)obj[F("pin")]);
|
||||
}
|
||||
}
|
||||
}
|
||||
oappend(SET_F("];"));
|
||||
}*/
|
||||
if (i) oappend(SET_F(","));
|
||||
oappend(SET_F("6,7,8,9,10,11")); // flash memory pins
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
oappend(SET_F(",2")); // DMX hardcoded pin
|
||||
#endif
|
||||
#ifdef WLED_ENABLE_ADALIGHT
|
||||
// inform settings page that pin 3 is used by ADALights if not aleready used by strip (previous setup)
|
||||
// NOTE: this will prohibit pin 3 use on new installs
|
||||
{
|
||||
bool pin3used = false;
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
Bus* bus = busses.getBus(s);
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) {
|
||||
if (pins[i] == 3) {
|
||||
pin3used = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pin3used) break;
|
||||
}
|
||||
if (!pin3used && pinManager.isPinAllocated(3)) oappend(SET_F(",3")); // ADALight (RX) pin
|
||||
}
|
||||
#endif
|
||||
#ifdef WLED_DEBUG
|
||||
oappend(SET_F(",1")); // debug output (TX) pin
|
||||
#endif
|
||||
}
|
||||
oappend(SET_F("];"));
|
||||
|
||||
// set limits
|
||||
oappend(SET_F("bLimits("));
|
||||
oappend(itoa(WLED_MAX_BUSSES,nS,10));
|
||||
oappend(",");
|
||||
@@ -280,13 +320,10 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
oappend(itoa(MAX_LED_MEMORY,nS,10));
|
||||
oappend(SET_F(");"));
|
||||
|
||||
oappend(SET_F("d.Sf.LC.max=")); //TODO Formula for max LEDs on ESP8266 depending on types. 500 DMA or 1500 UART (about 4kB mem usage)
|
||||
oappendi(MAX_LEDS);
|
||||
oappend(";");
|
||||
|
||||
sappend('v',SET_F("LC"),ledCount);
|
||||
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++){
|
||||
bool skip = false;
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
Bus* bus = busses.getBus(s);
|
||||
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
|
||||
@@ -294,18 +331,21 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type
|
||||
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
|
||||
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
|
||||
char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||
oappend(SET_F("addLEDs(1);"));
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) {
|
||||
lp[1] = 48+i;
|
||||
if (pinManager.isPinOk(pins[i])) sappend('v', lp, pins[i]);
|
||||
if (pinManager.isPinOk(pins[i])) sappend('v',lp,pins[i]);
|
||||
}
|
||||
sappend('v', lc, bus->getLength());
|
||||
sappend('v',lc,bus->getLength());
|
||||
sappend('v',lt,bus->getType());
|
||||
sappend('v',co,bus->getColorOrder());
|
||||
sappend('v',ls,bus->getStart());
|
||||
sappend('c',cv,bus->reversed);
|
||||
sappend('c',ew,bus->isRgbw());
|
||||
if (!skip) skip = bus->skipFirstLed()>0;
|
||||
}
|
||||
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
|
||||
sappend('v',SET_F("LA"),strip.milliampsPerLed);
|
||||
@@ -318,7 +358,6 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
|
||||
sappend('v',SET_F("CA"),briS);
|
||||
|
||||
sappend('v',SET_F("AW"),strip.rgbwMode);
|
||||
|
||||
sappend('c',SET_F("BO"),turnOnAtBoot);
|
||||
@@ -334,12 +373,11 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("TL"),nightlightDelayMinsDefault);
|
||||
sappend('v',SET_F("TW"),nightlightMode);
|
||||
sappend('i',SET_F("PB"),strip.paletteBlend);
|
||||
sappend('c',SET_F("SL"),skipFirstLed);
|
||||
sappend('c',SET_F("SL"),skip);
|
||||
sappend('v',SET_F("RL"),rlyPin);
|
||||
sappend('c',SET_F("RM"),rlyMde);
|
||||
sappend('v',SET_F("BT"),btnPin);
|
||||
sappend('v',SET_F("IR"),irPin);
|
||||
sappend('v',SET_F("AX"),auxPin);
|
||||
}
|
||||
|
||||
if (subPage == 3)
|
||||
@@ -435,8 +473,16 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('i',SET_F("TZ"),currentTimezone);
|
||||
sappend('v',SET_F("UO"),utcOffsetSecs);
|
||||
char tm[32];
|
||||
dtostrf(longitude,4,2,tm);
|
||||
sappends('s',SET_F("LN"),tm);
|
||||
dtostrf(latitude,4,2,tm);
|
||||
sappends('s',SET_F("LT"),tm);
|
||||
getTimeString(tm);
|
||||
sappends('m',SET_F("(\"times\")[0]"),tm);
|
||||
if ((int)(longitude*10.) || (int)(latitude*10.)) {
|
||||
sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset));
|
||||
sappends('m',SET_F("(\"times\")[1]"),tm);
|
||||
}
|
||||
sappend('i',SET_F("OL"),overlayCurrent);
|
||||
sappend('v',SET_F("O1"),overlayMin);
|
||||
sappend('v',SET_F("O2"),overlayMax);
|
||||
@@ -463,10 +509,10 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
char k[4];
|
||||
k[2] = 0; //Time macros
|
||||
for (int i = 0; i<8; i++)
|
||||
for (int i = 0; i<10; i++)
|
||||
{
|
||||
k[1] = 48+i; //ascii 0,1,2,3
|
||||
k[0] = 'H'; sappend('v',k,timerHours[i]);
|
||||
if (i<8) { k[0] = 'H'; sappend('v',k,timerHours[i]); }
|
||||
k[0] = 'N'; sappend('v',k,timerMinutes[i]);
|
||||
k[0] = 'T'; sappend('v',k,timerMacro[i]);
|
||||
k[0] = 'W'; sappend('v',k,timerWeekday[i]);
|
||||
|
||||
Reference in New Issue
Block a user