Fix spelling error
This commit is contained in:
commit
ea69957ed1
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,3 +15,4 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.idea
|
.idea
|
||||||
.direnv
|
.direnv
|
||||||
|
wled-update.sh
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.13.0-b2",
|
"version": "0.13.0-bl2",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.13.0-b2",
|
"version": "0.13.0-bl3",
|
||||||
"description": "Tools for WLED project",
|
"description": "Tools for WLED project",
|
||||||
"main": "tools/cdata.js",
|
"main": "tools/cdata.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -166,7 +166,7 @@ lib_deps =
|
|||||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||||
#TFT_eSPI
|
#TFT_eSPI
|
||||||
#For use SSD1306 OLED display uncomment following
|
#For use SSD1306 OLED display uncomment following
|
||||||
#U8g2@~2.27.2
|
U8g2@~2.28.8
|
||||||
#For Dallas sensor uncomment following 2 lines
|
#For Dallas sensor uncomment following 2 lines
|
||||||
#OneWire@~2.3.5
|
#OneWire@~2.3.5
|
||||||
#milesburton/DallasTemperature@^3.9.0
|
#milesburton/DallasTemperature@^3.9.0
|
||||||
|
6
tools/WLED_ESP32-wrover_4MB.csv
Normal file
6
tools/WLED_ESP32-wrover_4MB.csv
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xe000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x180000,
|
||||||
|
app1, app, ota_1, 0x190000,0x180000,
|
||||||
|
spiffs, data, spiffs, 0x310000,0xF0000,
|
|
@ -65,7 +65,7 @@ function adoptVersionAndRepo(html) {
|
|||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeHtmlGzipped(sourceFile, resultFile) {
|
function writeHtmlGzipped(sourceFile, resultFile, page) {
|
||||||
console.info("Reading " + sourceFile);
|
console.info("Reading " + sourceFile);
|
||||||
new inliner(sourceFile, function (error, html) {
|
new inliner(sourceFile, function (error, html) {
|
||||||
console.info("Inlined " + html.length + " characters");
|
console.info("Inlined " + html.length + " characters");
|
||||||
@ -95,8 +95,8 @@ function writeHtmlGzipped(sourceFile, resultFile) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Autogenerated from ${sourceFile}, do not edit!!
|
// Autogenerated from ${sourceFile}, do not edit!!
|
||||||
const uint16_t PAGE_index_L = ${result.length};
|
const uint16_t PAGE_${page}_L = ${result.length};
|
||||||
const uint8_t PAGE_index[] PROGMEM = {
|
const uint8_t PAGE_${page}[] PROGMEM = {
|
||||||
${array}
|
${array}
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
@ -194,7 +194,8 @@ function writeChunks(srcDir, specs, resultFile) {
|
|||||||
fs.writeFileSync(resultFile, src);
|
fs.writeFileSync(resultFile, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h");
|
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index');
|
||||||
|
writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple');
|
||||||
|
|
||||||
writeChunks(
|
writeChunks(
|
||||||
"wled00/data",
|
"wled00/data",
|
||||||
|
@ -458,11 +458,15 @@ class Animated_Staircase : public Usermod {
|
|||||||
|
|
||||||
useUSSensorTop = top[FPSTR(_useTopUltrasoundSensor)] | useUSSensorTop;
|
useUSSensorTop = top[FPSTR(_useTopUltrasoundSensor)] | useUSSensorTop;
|
||||||
topPIRorTriggerPin = top[FPSTR(_topPIRorTrigger_pin)] | topPIRorTriggerPin;
|
topPIRorTriggerPin = top[FPSTR(_topPIRorTrigger_pin)] | topPIRorTriggerPin;
|
||||||
|
// topPIRorTriggerPin = min(33,max(-1,(int)topPIRorTriggerPin)); // bounds check
|
||||||
topEchoPin = top[FPSTR(_topEcho_pin)] | topEchoPin;
|
topEchoPin = top[FPSTR(_topEcho_pin)] | topEchoPin;
|
||||||
|
// topEchoPin = min(39,max(-1,(int)topEchoPin)); // bounds check
|
||||||
|
|
||||||
useUSSensorBottom = top[FPSTR(_useBottomUltrasoundSensor)] | useUSSensorBottom;
|
useUSSensorBottom = top[FPSTR(_useBottomUltrasoundSensor)] | useUSSensorBottom;
|
||||||
bottomPIRorTriggerPin = top[FPSTR(_bottomPIRorTrigger_pin)] | bottomPIRorTriggerPin;
|
bottomPIRorTriggerPin = top[FPSTR(_bottomPIRorTrigger_pin)] | bottomPIRorTriggerPin;
|
||||||
|
// bottomPIRorTriggerPin = min(33,max(-1,(int)bottomPIRorTriggerPin)); // bounds check
|
||||||
bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin;
|
bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin;
|
||||||
|
// bottomEchoPin = min(39,max(-1,(int)bottomEchoPin)); // bounds check
|
||||||
|
|
||||||
topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist;
|
topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist;
|
||||||
topMaxDist = min(150,max(30,(int)topMaxDist)); // max distnace ~1.5m (a lag of 9ms may be expected)
|
topMaxDist = min(150,max(30,(int)topMaxDist)); // max distnace ~1.5m (a lag of 9ms may be expected)
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
# JSON IR remote
|
# JSON IR remote
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
The JSON IR remote allows users to customize IR remote behavior without writing custom code and compiling.
|
The JSON IR remote allows users to customize IR remote behavior without writing custom code and compiling.
|
||||||
It also enables using any remote that is compatible with your IR receiver. Using the JSON IR remote, you can
|
It also enables using any remote that is compatible with your IR receiver. Using the JSON IR remote, you can
|
||||||
map buttons from any remote to any HTTP request API or JSON API command.
|
map buttons from any remote to any HTTP request API or JSON API command.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
* Upload the IR config file, named _ir.json_ to your board using the [ip address]/edit url. Pick from one of the included files or create your own.
|
* Upload the IR config file, named _ir.json_ to your board using the [ip address]/edit url. Pick from one of the included files or create your own.
|
||||||
* On the config > LED settings page, set the correct IR pin.
|
* On the config > LED settings page, set the correct IR pin.
|
||||||
* On the config > Sync Interfaces page, select "JSON Remote" as the Infrared remote.
|
* On the config > Sync Interfaces page, select "JSON Remote" as the Infrared remote.
|
||||||
|
|
||||||
## Modification
|
## Modification
|
||||||
|
|
||||||
* See if there is a json file with the same number of buttons as your remote. Many remotes will have the same internals and emit the same codes but have different labels.
|
* See if there is a json file with the same number of buttons as your remote. Many remotes will have the same internals and emit the same codes but have different labels.
|
||||||
* In the ir.json file, each key will be the hex encoded IR code.
|
* In the ir.json file, each key will be the hex encoded IR code.
|
||||||
* The "cmd" property will be the HTTP Request API or JSON API to execute when that button is pressed.
|
* The "cmd" property will be the HTTP Request API or JSON API to execute when that button is pressed.
|
||||||
* A limited number of c functions are supported (!incBrightness, !decBrightness, !presetFallback)
|
* A limited number of c functions are supported (!incBrightness, !decBrightness, !presetFallback)
|
||||||
* When using !presetFallback, include properties PL (preset to load), FX (effect to fall back to) and FP (palette to fall back to)
|
* When using !presetFallback, include properties PL (preset to load), FX (effect to fall back to) and FP (palette to fall back to)
|
||||||
* If the command is _repeatable_ and does not contain the "~" character, add a "rpt": true property.
|
* If the command is _repeatable_ and does not contain the "~" character, add a "rpt": true property.
|
||||||
* Other properties are ignored, but having a label property may help when editing.
|
* Other properties are ignored, but having a label property may help when editing.
|
||||||
|
|
||||||
|
|
||||||
Sample:
|
Sample:
|
||||||
{
|
{
|
||||||
"0xFF629D": {"cmd": "T=2", "rpt": true, "label": "Toggle on/off"}, // HTTP command
|
"0xFF629D": {"cmd": "T=2", "rpt": true, "label": "Toggle on/off"}, // HTTP command
|
||||||
"0xFF9867": {"cmd": "A=~16", "label": "Inc brightness"}, // HTTP command with incrementing
|
"0xFF9867": {"cmd": "A=~16", "label": "Inc brightness"}, // HTTP command with incrementing
|
||||||
"0xFF38C7": {"cmd": {"bri": 10}, "label": "Dim to 10"}, // JSON command
|
"0xFF38C7": {"cmd": {"bri": 10}, "label": "Dim to 10"}, // JSON command
|
||||||
"0xFF22DD": {"cmd": "!presetFallback", "PL": 1, "FX": 16, "FP": 6,
|
"0xFF22DD": {"cmd": "!presetFallback", "PL": 1, "FX": 16, "FP": 6,
|
||||||
"label": "Preset 1 or fallback to Saw - Party"}, // c function
|
"label": "Preset 1 or fallback to Saw - Party"}, // c function
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
# PIR sensor with MQTT
|
|
||||||
|
|
||||||
This simple usermod allows attaching a PIR sensor like the AM312 and publish the readings over MQTT. A message is sent when motion is detected as well as when motion has stopped.
|
|
||||||
|
|
||||||
This usermod has only been tested with the AM312 sensor though should work for any other PIR sensor. Note that this does not control the LED strip directly, it only publishes MQTT readings for use with other integrations like Home Assistant.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Copy and replace the file `usermod.cpp` in wled00 directory.
|
|
@ -1,55 +0,0 @@
|
|||||||
#include "wled.h"
|
|
||||||
/*
|
|
||||||
* This v1 usermod file allows you to add own functionality to WLED more easily
|
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
|
||||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
|
||||||
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
|
|
||||||
*
|
|
||||||
* Consider the v2 usermod API if you need a more advanced feature set!
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
|
||||||
|
|
||||||
// PIR sensor pin
|
|
||||||
const int MOTION_PIN = 16;
|
|
||||||
// MQTT topic for sensor values
|
|
||||||
const char MQTT_TOPIC[] = "/motion";
|
|
||||||
|
|
||||||
int prevState = LOW;
|
|
||||||
|
|
||||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
|
||||||
void userSetup()
|
|
||||||
{
|
|
||||||
pinMode(MOTION_PIN, INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
|
||||||
void userConnected()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void publishMqtt(String state)
|
|
||||||
{
|
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
|
||||||
if (mqtt != nullptr){
|
|
||||||
char subuf[38];
|
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
|
||||||
strcat(subuf, MQTT_TOPIC);
|
|
||||||
mqtt->publish(subuf, 0, true, state.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
|
||||||
void userLoop()
|
|
||||||
{
|
|
||||||
if (digitalRead(MOTION_PIN) == HIGH && prevState == LOW) { // Motion detected
|
|
||||||
publishMqtt("ON");
|
|
||||||
prevState = HIGH;
|
|
||||||
}
|
|
||||||
if (digitalRead(MOTION_PIN) == LOW && prevState == HIGH) { // Motion stopped
|
|
||||||
publishMqtt("OFF");
|
|
||||||
prevState = LOW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,409 +1,409 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
#ifndef PIR_SENSOR_PIN
|
#ifndef PIR_SENSOR_PIN
|
||||||
// compatible with QuinLED-Dig-Uno
|
// compatible with QuinLED-Dig-Uno
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
#define PIR_SENSOR_PIN 23 // Q4
|
#define PIR_SENSOR_PIN 23 // Q4
|
||||||
#else //ESP8266 boards
|
#else //ESP8266 boards
|
||||||
#define PIR_SENSOR_PIN 13 // Q4 (D7 on D1 mini)
|
#define PIR_SENSOR_PIN 13 // Q4 (D7 on D1 mini)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This usermod handles PIR sensor states.
|
* This usermod handles PIR sensor states.
|
||||||
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
||||||
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
|
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Usermods allow you to add own functionality to WLED more easily
|
* Usermods allow you to add own functionality to WLED more easily
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||||
*
|
*
|
||||||
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
|
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
|
||||||
* Multiple v2 usermods can be added to one compilation easily.
|
* Multiple v2 usermods can be added to one compilation easily.
|
||||||
*
|
*
|
||||||
* Creating a usermod:
|
* Creating a usermod:
|
||||||
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
|
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
|
||||||
* Please remember to rename the class and file to a descriptive name.
|
* Please remember to rename the class and file to a descriptive name.
|
||||||
* You may also use multiple .h and .cpp files.
|
* You may also use multiple .h and .cpp files.
|
||||||
*
|
*
|
||||||
* Using a usermod:
|
* Using a usermod:
|
||||||
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
||||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PIRsensorSwitch : public Usermod
|
class PIRsensorSwitch : public Usermod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
*/
|
*/
|
||||||
PIRsensorSwitch() {}
|
PIRsensorSwitch() {}
|
||||||
/**
|
/**
|
||||||
* desctructor
|
* desctructor
|
||||||
*/
|
*/
|
||||||
~PIRsensorSwitch() {}
|
~PIRsensorSwitch() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable/Disable the PIR sensor
|
* Enable/Disable the PIR sensor
|
||||||
*/
|
*/
|
||||||
void EnablePIRsensor(bool en) { enabled = en; }
|
void EnablePIRsensor(bool en) { enabled = en; }
|
||||||
/**
|
/**
|
||||||
* Get PIR sensor enabled/disabled state
|
* Get PIR sensor enabled/disabled state
|
||||||
*/
|
*/
|
||||||
bool PIRsensorEnabled() { return enabled; }
|
bool PIRsensorEnabled() { return enabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// PIR sensor pin
|
// PIR sensor pin
|
||||||
int8_t PIRsensorPin = PIR_SENSOR_PIN;
|
int8_t PIRsensorPin = PIR_SENSOR_PIN;
|
||||||
// notification mode for colorUpdated()
|
// notification mode for colorUpdated()
|
||||||
const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE
|
const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE
|
||||||
// delay before switch off after the sensor state goes LOW
|
// delay before switch off after the sensor state goes LOW
|
||||||
uint32_t m_switchOffDelay = 600000; // 10min
|
uint32_t m_switchOffDelay = 600000; // 10min
|
||||||
// off timer start time
|
// off timer start time
|
||||||
uint32_t m_offTimerStart = 0;
|
uint32_t m_offTimerStart = 0;
|
||||||
// current PIR sensor pin state
|
// current PIR sensor pin state
|
||||||
byte sensorPinState = LOW;
|
byte sensorPinState = LOW;
|
||||||
// PIR sensor enabled
|
// PIR sensor enabled
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
// status of initialisation
|
// status of initialisation
|
||||||
bool initDone = false;
|
bool initDone = false;
|
||||||
// on and off presets
|
// on and off presets
|
||||||
uint8_t m_onPreset = 0;
|
uint8_t m_onPreset = 0;
|
||||||
uint8_t m_offPreset = 0;
|
uint8_t m_offPreset = 0;
|
||||||
// flag to indicate that PIR sensor should activate WLED during nighttime only
|
// flag to indicate that PIR sensor should activate WLED during nighttime only
|
||||||
bool m_nightTimeOnly = false;
|
bool m_nightTimeOnly = false;
|
||||||
// flag to send MQTT message only (assuming it is enabled)
|
// flag to send MQTT message only (assuming it is enabled)
|
||||||
bool m_mqttOnly = false;
|
bool m_mqttOnly = false;
|
||||||
// flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR)
|
// flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR)
|
||||||
bool m_offOnly = false;
|
bool m_offOnly = false;
|
||||||
bool PIRtriggered = false;
|
bool PIRtriggered = false;
|
||||||
|
|
||||||
unsigned long lastLoop = 0;
|
unsigned long lastLoop = 0;
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
static const char _name[];
|
static const char _name[];
|
||||||
static const char _switchOffDelay[];
|
static const char _switchOffDelay[];
|
||||||
static const char _enabled[];
|
static const char _enabled[];
|
||||||
static const char _onPreset[];
|
static const char _onPreset[];
|
||||||
static const char _offPreset[];
|
static const char _offPreset[];
|
||||||
static const char _nightTime[];
|
static const char _nightTime[];
|
||||||
static const char _mqttOnly[];
|
static const char _mqttOnly[];
|
||||||
static const char _offOnly[];
|
static const char _offOnly[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check if it is daytime
|
* check if it is daytime
|
||||||
* if sunrise/sunset is not defined (no NTP or lat/lon) default to nighttime
|
* if sunrise/sunset is not defined (no NTP or lat/lon) default to nighttime
|
||||||
*/
|
*/
|
||||||
bool isDayTime() {
|
bool isDayTime() {
|
||||||
bool isDayTime = false;
|
bool isDayTime = false;
|
||||||
updateLocalTime();
|
updateLocalTime();
|
||||||
uint8_t hr = hour(localTime);
|
uint8_t hr = hour(localTime);
|
||||||
uint8_t mi = minute(localTime);
|
uint8_t mi = minute(localTime);
|
||||||
|
|
||||||
if (sunrise && sunset) {
|
if (sunrise && sunset) {
|
||||||
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
||||||
isDayTime = true;
|
isDayTime = true;
|
||||||
} else {
|
} else {
|
||||||
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
||||||
isDayTime = true;
|
isDayTime = true;
|
||||||
}
|
}
|
||||||
if (hour(sunset)==hr && minute(sunset)>mi) {
|
if (hour(sunset)==hr && minute(sunset)>mi) {
|
||||||
isDayTime = true;
|
isDayTime = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isDayTime;
|
return isDayTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch strip on/off
|
* switch strip on/off
|
||||||
*/
|
*/
|
||||||
void switchStrip(bool switchOn)
|
void switchStrip(bool switchOn)
|
||||||
{
|
{
|
||||||
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return;
|
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return;
|
||||||
PIRtriggered = switchOn;
|
PIRtriggered = switchOn;
|
||||||
if (switchOn && m_onPreset) {
|
if (switchOn && m_onPreset) {
|
||||||
applyPreset(m_onPreset);
|
applyPreset(m_onPreset);
|
||||||
} else if (!switchOn && m_offPreset) {
|
} else if (!switchOn && m_offPreset) {
|
||||||
applyPreset(m_offPreset);
|
applyPreset(m_offPreset);
|
||||||
} else if (switchOn && bri == 0) {
|
} else if (switchOn && bri == 0) {
|
||||||
bri = briLast;
|
bri = briLast;
|
||||||
colorUpdated(NotifyUpdateMode);
|
colorUpdated(NotifyUpdateMode);
|
||||||
} else if (!switchOn && bri != 0) {
|
} else if (!switchOn && bri != 0) {
|
||||||
briLast = bri;
|
briLast = bri;
|
||||||
bri = 0;
|
bri = 0;
|
||||||
colorUpdated(NotifyUpdateMode);
|
colorUpdated(NotifyUpdateMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishMqtt(const char* state)
|
void publishMqtt(const char* state)
|
||||||
{
|
{
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
if (WLED_MQTT_CONNECTED){
|
if (WLED_MQTT_CONNECTED){
|
||||||
char subuf[64];
|
char subuf[64];
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
strcpy(subuf, mqttDeviceTopic);
|
||||||
strcat_P(subuf, PSTR("/motion"));
|
strcat_P(subuf, PSTR("/motion"));
|
||||||
mqtt->publish(subuf, 0, false, state);
|
mqtt->publish(subuf, 0, false, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read and update PIR sensor state.
|
* Read and update PIR sensor state.
|
||||||
* Initilize/reset switch off timer
|
* Initilize/reset switch off timer
|
||||||
*/
|
*/
|
||||||
bool updatePIRsensorState()
|
bool updatePIRsensorState()
|
||||||
{
|
{
|
||||||
bool pinState = digitalRead(PIRsensorPin);
|
bool pinState = digitalRead(PIRsensorPin);
|
||||||
if (pinState != sensorPinState) {
|
if (pinState != sensorPinState) {
|
||||||
sensorPinState = pinState; // change previous state
|
sensorPinState = pinState; // change previous state
|
||||||
|
|
||||||
if (sensorPinState == HIGH) {
|
if (sensorPinState == HIGH) {
|
||||||
m_offTimerStart = 0;
|
m_offTimerStart = 0;
|
||||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
||||||
publishMqtt("on");
|
publishMqtt("on");
|
||||||
} else /*if (bri != 0)*/ {
|
} else /*if (bri != 0)*/ {
|
||||||
// start switch off timer
|
// start switch off timer
|
||||||
m_offTimerStart = millis();
|
m_offTimerStart = millis();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch off the strip if the delay has elapsed
|
* switch off the strip if the delay has elapsed
|
||||||
*/
|
*/
|
||||||
bool handleOffTimer()
|
bool handleOffTimer()
|
||||||
{
|
{
|
||||||
if (m_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay)
|
if (m_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay)
|
||||||
{
|
{
|
||||||
if (enabled == true)
|
if (enabled == true)
|
||||||
{
|
{
|
||||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(false);
|
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(false);
|
||||||
publishMqtt("off");
|
publishMqtt("off");
|
||||||
}
|
}
|
||||||
m_offTimerStart = 0;
|
m_offTimerStart = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||||
* You can use it to initialize variables, sensors or similar.
|
* You can use it to initialize variables, sensors or similar.
|
||||||
*/
|
*/
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||||
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||||
// PIR Sensor mode INPUT_PULLUP
|
// PIR Sensor mode INPUT_PULLUP
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||||
sensorPinState = digitalRead(PIRsensorPin);
|
sensorPinState = digitalRead(PIRsensorPin);
|
||||||
} else {
|
} else {
|
||||||
if (PIRsensorPin >= 0) {
|
if (PIRsensorPin >= 0) {
|
||||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||||
}
|
}
|
||||||
PIRsensorPin = -1; // allocation failed
|
PIRsensorPin = -1; // allocation failed
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* connected() is called every time the WiFi is (re)connected
|
* connected() is called every time the WiFi is (re)connected
|
||||||
* Use it to initialize network interfaces
|
* Use it to initialize network interfaces
|
||||||
*/
|
*/
|
||||||
void connected()
|
void connected()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
*/
|
*/
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// only check sensors 4x/s
|
// only check sensors 4x/s
|
||||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||||
lastLoop = millis();
|
lastLoop = millis();
|
||||||
|
|
||||||
if (!updatePIRsensorState()) {
|
if (!updatePIRsensorState()) {
|
||||||
handleOffTimer();
|
handleOffTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
*
|
*
|
||||||
* Add PIR sensor state and switch off timer duration to jsoninfo
|
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||||
*/
|
*/
|
||||||
void addToJsonInfo(JsonObject &root)
|
void addToJsonInfo(JsonObject &root)
|
||||||
{
|
{
|
||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
// off timer
|
// off timer
|
||||||
String uiDomString = F("PIR <i class=\"icons\"></i>");
|
String uiDomString = F("PIR <i class=\"icons\"></i>");
|
||||||
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
|
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
|
||||||
if (m_offTimerStart > 0)
|
if (m_offTimerStart > 0)
|
||||||
{
|
{
|
||||||
uiDomString = "";
|
uiDomString = "";
|
||||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
|
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
|
||||||
if (offSeconds >= 3600)
|
if (offSeconds >= 3600)
|
||||||
{
|
{
|
||||||
uiDomString += (offSeconds / 3600);
|
uiDomString += (offSeconds / 3600);
|
||||||
uiDomString += F("h ");
|
uiDomString += F("h ");
|
||||||
offSeconds %= 3600;
|
offSeconds %= 3600;
|
||||||
}
|
}
|
||||||
if (offSeconds >= 60)
|
if (offSeconds >= 60)
|
||||||
{
|
{
|
||||||
uiDomString += (offSeconds / 60);
|
uiDomString += (offSeconds / 60);
|
||||||
offSeconds %= 60;
|
offSeconds %= 60;
|
||||||
}
|
}
|
||||||
else if (uiDomString.length() > 0)
|
else if (uiDomString.length() > 0)
|
||||||
{
|
{
|
||||||
uiDomString += 0;
|
uiDomString += 0;
|
||||||
}
|
}
|
||||||
if (uiDomString.length() > 0)
|
if (uiDomString.length() > 0)
|
||||||
{
|
{
|
||||||
uiDomString += F("min ");
|
uiDomString += F("min ");
|
||||||
}
|
}
|
||||||
uiDomString += (offSeconds);
|
uiDomString += (offSeconds);
|
||||||
infoArr.add(uiDomString + F("s"));
|
infoArr.add(uiDomString + F("s"));
|
||||||
} else {
|
} else {
|
||||||
infoArr.add(sensorPinState ? F("sensor on") : F("inactive"));
|
infoArr.add(sensorPinState ? F("sensor on") : F("inactive"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String uiDomString = F("PIR sensor");
|
String uiDomString = F("PIR sensor");
|
||||||
JsonArray infoArr = user.createNestedArray(uiDomString);
|
JsonArray infoArr = user.createNestedArray(uiDomString);
|
||||||
infoArr.add(F("disabled"));
|
infoArr.add(F("disabled"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void addToJsonState(JsonObject &root)
|
void addToJsonState(JsonObject &root)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void readFromJsonState(JsonObject &root)
|
void readFromJsonState(JsonObject &root)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provide the changeable values
|
* provide the changeable values
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject &root)
|
void addToConfig(JsonObject &root)
|
||||||
{
|
{
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
||||||
top["pin"] = PIRsensorPin;
|
top["pin"] = PIRsensorPin;
|
||||||
top[FPSTR(_onPreset)] = m_onPreset;
|
top[FPSTR(_onPreset)] = m_onPreset;
|
||||||
top[FPSTR(_offPreset)] = m_offPreset;
|
top[FPSTR(_offPreset)] = m_offPreset;
|
||||||
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
||||||
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
||||||
top[FPSTR(_offOnly)] = m_offOnly;
|
top[FPSTR(_offOnly)] = m_offOnly;
|
||||||
DEBUG_PRINTLN(F("PIR config saved."));
|
DEBUG_PRINTLN(F("PIR config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* restore the changeable values
|
* restore the changeable values
|
||||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||||
*
|
*
|
||||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
*/
|
*/
|
||||||
bool readFromConfig(JsonObject &root)
|
bool readFromConfig(JsonObject &root)
|
||||||
{
|
{
|
||||||
bool oldEnabled = enabled;
|
bool oldEnabled = enabled;
|
||||||
int8_t oldPin = PIRsensorPin;
|
int8_t oldPin = PIRsensorPin;
|
||||||
|
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PIRsensorPin = top["pin"] | PIRsensorPin;
|
PIRsensorPin = top["pin"] | PIRsensorPin;
|
||||||
|
|
||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
|
|
||||||
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
||||||
|
|
||||||
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
||||||
m_onPreset = max(0,min(250,(int)m_onPreset));
|
m_onPreset = max(0,min(250,(int)m_onPreset));
|
||||||
|
|
||||||
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
||||||
m_offPreset = max(0,min(250,(int)m_offPreset));
|
m_offPreset = max(0,min(250,(int)m_offPreset));
|
||||||
|
|
||||||
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
||||||
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
||||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// reading config prior to setup()
|
// reading config prior to setup()
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
||||||
// check if pin is OK
|
// check if pin is OK
|
||||||
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
||||||
// if we are changing pin in settings page
|
// if we are changing pin in settings page
|
||||||
// deallocate old pin
|
// deallocate old pin
|
||||||
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
||||||
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||||
} else {
|
} else {
|
||||||
// allocation failed
|
// allocation failed
|
||||||
PIRsensorPin = -1;
|
PIRsensorPin = -1;
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
sensorPinState = digitalRead(PIRsensorPin);
|
sensorPinState = digitalRead(PIRsensorPin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_offOnly)].isNull();
|
return !top[FPSTR(_offOnly)].isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||||
*/
|
*/
|
||||||
uint16_t getId()
|
uint16_t getId()
|
||||||
{
|
{
|
||||||
return USERMOD_ID_PIRSWITCH;
|
return USERMOD_ID_PIRSWITCH;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
||||||
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
||||||
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
||||||
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
||||||
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
||||||
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
||||||
const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
||||||
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
# QuinLED Dig Uno board
|
|
||||||
|
|
||||||
These files allow WLED 0.9.1 to report the temp sensor on the Quinled board to MQTT. I use it to report the board temp to Home Assistant via MQTT, so it will send notifications if something happens and the board start to heat up.
|
|
||||||
This code uses Aircookie's WLED software. It has a premade file for user modifications. I use it to publish the temperature from the dallas temperature sensor on the Quinled board. The entries for the top of the WLED00 file, initializes the required libraries, and variables for the sensor. The .ino file waits for 60 seconds, and checks to see if the MQTT server is connected (thanks Aircoookie). It then poles the sensor, and published it using the MQTT service already running, using the main topic programmed in the WLED UI.
|
|
||||||
|
|
||||||
Installation of file: Copy and replace file in wled00 directory
|
|
||||||
|
|
||||||
## Project link
|
|
||||||
|
|
||||||
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
|
|
||||||
|
|
||||||
### Platformio requirements
|
|
||||||
|
|
||||||
Uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
# platformio.ini
|
|
||||||
...
|
|
||||||
[platformio]
|
|
||||||
...
|
|
||||||
; default_envs = esp07
|
|
||||||
default_envs = d1_mini
|
|
||||||
...
|
|
||||||
[common]
|
|
||||||
...
|
|
||||||
lib_deps_external =
|
|
||||||
...
|
|
||||||
#For use SSD1306 OLED display uncomment following
|
|
||||||
U8g2@~2.27.3
|
|
||||||
#For Dallas sensor uncomment following 2 lines
|
|
||||||
DallasTemperature@~3.8.0
|
|
||||||
OneWire@~2.3.5
|
|
||||||
...
|
|
||||||
```
|
|
@ -1,54 +0,0 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include "wled.h"
|
|
||||||
//Intiating code for QuinLED Dig-Uno temp sensor
|
|
||||||
//Uncomment Celsius if that is your prefered temperature scale
|
|
||||||
#include <DallasTemperature.h> //Dallastemperature sensor
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
|
||||||
OneWire oneWire(18);
|
|
||||||
#else //ESP8266 boards
|
|
||||||
OneWire oneWire(14);
|
|
||||||
#endif
|
|
||||||
DallasTemperature sensor(&oneWire);
|
|
||||||
long temptimer = millis();
|
|
||||||
long lastMeasure = 0;
|
|
||||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
|
||||||
void userSetup()
|
|
||||||
{
|
|
||||||
// Start the DS18B20 sensor
|
|
||||||
sensor.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
|
||||||
void userConnected()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void userLoop()
|
|
||||||
{
|
|
||||||
temptimer = millis();
|
|
||||||
|
|
||||||
// Timer to publishe new temperature every 60 seconds
|
|
||||||
if (temptimer - lastMeasure > 60000) {
|
|
||||||
lastMeasure = temptimer;
|
|
||||||
|
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
|
||||||
if (mqtt != nullptr){
|
|
||||||
sensor.requestTemperatures();
|
|
||||||
|
|
||||||
//Gets prefered temperature scale based on selection in definitions section
|
|
||||||
#ifdef Celsius
|
|
||||||
float board_temperature = sensor.getTempCByIndex(0);
|
|
||||||
#else
|
|
||||||
float board_temperature = sensors.getTempFByIndex(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server.
|
|
||||||
char subuf[38];
|
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
|
||||||
strcat(subuf, "/temperature");
|
|
||||||
mqtt->publish(subuf, 0, true, String(board_temperature).c_str());
|
|
||||||
return;}
|
|
||||||
return;}
|
|
||||||
return;
|
|
||||||
}
|
|
@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
This usermod allow to use 240x240 display to display following:
|
This usermod allow to use 240x240 display to display following:
|
||||||
|
|
||||||
|
* current date and time;
|
||||||
* Network SSID;
|
* Network SSID;
|
||||||
* IP address;
|
* IP address;
|
||||||
|
* WiFi signal strength;
|
||||||
* Brightness;
|
* Brightness;
|
||||||
* Chosen effect;
|
* Chosen effect;
|
||||||
* Chosen palette;
|
* Chosen palette;
|
||||||
|
* effect speed and intensity;
|
||||||
* Estimated current in mA;
|
* Estimated current in mA;
|
||||||
|
|
||||||
## Hardware
|
## Hardware
|
||||||
@ -46,27 +49,29 @@ Add lines to section:
|
|||||||
default_envs = esp32dev
|
default_envs = esp32dev
|
||||||
build_flags = ${common.build_flags_esp32}
|
build_flags = ${common.build_flags_esp32}
|
||||||
-D USERMOD_ST7789_DISPLAY
|
-D USERMOD_ST7789_DISPLAY
|
||||||
|
-DUSER_SETUP_LOADED=1
|
||||||
|
-DST7789_DRIVER=1
|
||||||
|
-DTFT_WIDTH=240
|
||||||
|
-DTFT_HEIGHT=240
|
||||||
|
-DCGRAM_OFFSET=1
|
||||||
|
-DTFT_MOSI=21
|
||||||
|
-DTFT_SCLK=22
|
||||||
|
-DTFT_DC=27
|
||||||
|
-DTFT_RST=26
|
||||||
|
-DTFT_BL=14
|
||||||
|
-DLOAD_GLCD=1
|
||||||
|
;optional for WROVER
|
||||||
|
;-DCONFIG_SPIRAM_SUPPORT=1
|
||||||
```
|
```
|
||||||
|
|
||||||
Save the `platformio.ini` file. Once this is saved, the required library files should be automatically downloaded for modifications in a later step.
|
Save the `platformio.ini` file. Once this is saved, the required library files should be automatically downloaded for modifications in a later step.
|
||||||
|
|
||||||
### TFT_eSPI Library Adjustments
|
### TFT_eSPI Library Adjustments
|
||||||
|
|
||||||
We need to modify a file in the `TFT_eSPI` library. If you followed the directions to modify and save the `platformio.ini` file above, the `User_Setup_Select.h` file can be found in the `/.pio/libdeps/esp32dev/TFT_eSPI` folder.
|
If you are not using PlatformIO you need to modify a file in the `TFT_eSPI` library. If you followed the directions to modify and save the `platformio.ini` file above, the `Setup24_ST7789.h` file can be found in the `/.pio/libdeps/esp32dev/TFT_eSPI/User_Setups/` folder.
|
||||||
|
|
||||||
Modify the `User_Setup_Select.h` file as follows:
|
Edit `Setup_ST7789.h` file and uncomment nad changep GPIO pin numbers in lines containing `TFT_MOSI`, `TFT_SCLK`, `TFT_RST`, `TFT_DC`.
|
||||||
|
|
||||||
* Comment out the following line (which is the 'default' setup file):
|
Modify the `User_Setup_Select.h` by uncommentig the line containing `#include <User_Setups/Setup24_ST7789.h>` and commenting out line containing `#include <User_Setup.h>`.
|
||||||
|
|
||||||
```ini
|
If your display includes backlight enable pin, #define TFT_BL with backlight enable GPIO number.
|
||||||
//#include <User_Setup.h> // Default setup is root library folder
|
|
||||||
```
|
|
||||||
|
|
||||||
* Add following line:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
#include <User_Setups/Setup_ST7789_Display.h> // Setup file for ESP32 ST7789V SPI bus TFT
|
|
||||||
```
|
|
||||||
|
|
||||||
* Copy file `"Setup_ST7789_Display.h"` from usermod folder to `/.pio/libdeps/esp32dev/TFT_eSPI/User_Setups`
|
|
@ -7,27 +7,48 @@
|
|||||||
#include <TFT_eSPI.h>
|
#include <TFT_eSPI.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
#define USERMOD_ST7789_DISPLAY 97
|
#ifndef USER_SETUP_LOADED
|
||||||
|
#ifndef ST7789_DRIVER
|
||||||
#ifndef TFT_DISPOFF
|
#error Please define ST7789_DRIVER
|
||||||
#define TFT_DISPOFF 0x28
|
#endif
|
||||||
|
#ifndef TFT_WIDTH
|
||||||
|
#error Please define TFT_WIDTH
|
||||||
|
#endif
|
||||||
|
#ifndef TFT_HEIGHT
|
||||||
|
#error Please define TFT_HEIGHT
|
||||||
|
#endif
|
||||||
|
#ifndef TFT_MOSI
|
||||||
|
#error Please define TFT_MOSI
|
||||||
|
#endif
|
||||||
|
#ifndef TFT_SCLK
|
||||||
|
#error Please define TFT_SCLK
|
||||||
|
#endif
|
||||||
|
#ifndef TFT_DC
|
||||||
|
#error Please define TFT_DC
|
||||||
|
#endif
|
||||||
|
#ifndef TFT_RST
|
||||||
|
#error Please define TFT_RST
|
||||||
|
#endif
|
||||||
|
#ifndef LOAD_GLCD
|
||||||
|
#error Please define LOAD_GLCD
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef TFT_BL
|
||||||
|
#define TFT_BL -1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TFT_SLPIN
|
#define USERMOD_ID_ST7789_DISPLAY 97
|
||||||
#define TFT_SLPIN 0x10
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TFT_MOSI 21
|
TFT_eSPI tft = TFT_eSPI(TFT_WIDTH, TFT_HEIGHT); // Invoke custom library
|
||||||
#define TFT_SCLK 22
|
|
||||||
#define TFT_DC 18
|
|
||||||
#define TFT_RST 5
|
|
||||||
#define TFT_BL 26 // Display backlight control pin
|
|
||||||
|
|
||||||
TFT_eSPI tft = TFT_eSPI(240, 240); // Invoke custom library
|
// Extra char (+1) for null
|
||||||
|
#define LINE_BUFFER_SIZE 20
|
||||||
|
|
||||||
// How often we are redrawing screen
|
// How often we are redrawing screen
|
||||||
#define USER_LOOP_REFRESH_RATE_MS 1000
|
#define USER_LOOP_REFRESH_RATE_MS 1000
|
||||||
|
|
||||||
|
extern int getSignalQuality(int rssi);
|
||||||
|
|
||||||
|
|
||||||
//class name. Use something descriptive and leave the ": public Usermod" part :)
|
//class name. Use something descriptive and leave the ": public Usermod" part :)
|
||||||
class St7789DisplayUsermod : public Usermod {
|
class St7789DisplayUsermod : public Usermod {
|
||||||
@ -45,9 +66,70 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
uint8_t knownBrightness = 0;
|
uint8_t knownBrightness = 0;
|
||||||
uint8_t knownMode = 0;
|
uint8_t knownMode = 0;
|
||||||
uint8_t knownPalette = 0;
|
uint8_t knownPalette = 0;
|
||||||
uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2
|
uint8_t knownEffectSpeed = 0;
|
||||||
|
uint8_t knownEffectIntensity = 0;
|
||||||
|
uint8_t knownMinute = 99;
|
||||||
|
uint8_t knownHour = 99;
|
||||||
|
|
||||||
|
const uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2
|
||||||
long lastUpdate = 0;
|
long lastUpdate = 0;
|
||||||
|
|
||||||
|
void center(String &line, uint8_t width) {
|
||||||
|
int len = line.length();
|
||||||
|
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
|
||||||
|
for (byte i=line.length(); i<width; i++) line += ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the current date and time in large characters
|
||||||
|
* on the middle rows. Based 24 or 12 hour depending on
|
||||||
|
* the useAMPM configuration.
|
||||||
|
*/
|
||||||
|
void showTime() {
|
||||||
|
if (!ntpEnabled) return;
|
||||||
|
char lineBuffer[LINE_BUFFER_SIZE];
|
||||||
|
|
||||||
|
updateLocalTime();
|
||||||
|
byte minuteCurrent = minute(localTime);
|
||||||
|
byte hourCurrent = hour(localTime);
|
||||||
|
byte secondCurrent = second(localTime);
|
||||||
|
knownMinute = minuteCurrent;
|
||||||
|
knownHour = hourCurrent;
|
||||||
|
|
||||||
|
byte currentMonth = month(localTime);
|
||||||
|
sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(currentMonth), day(localTime));
|
||||||
|
tft.setTextColor(TFT_SILVER);
|
||||||
|
tft.setCursor(84, 0);
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.print(lineBuffer);
|
||||||
|
|
||||||
|
byte showHour = hourCurrent;
|
||||||
|
boolean isAM = false;
|
||||||
|
if (useAMPM) {
|
||||||
|
if (showHour == 0) {
|
||||||
|
showHour = 12;
|
||||||
|
isAM = true;
|
||||||
|
} else if (showHour > 12) {
|
||||||
|
showHour -= 12;
|
||||||
|
isAM = false;
|
||||||
|
} else {
|
||||||
|
isAM = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf_P(lineBuffer, PSTR("%2d:%02d"), (useAMPM ? showHour : hourCurrent), minuteCurrent);
|
||||||
|
tft.setTextColor(TFT_WHITE);
|
||||||
|
tft.setTextSize(4);
|
||||||
|
tft.setCursor(60, 24);
|
||||||
|
tft.print(lineBuffer);
|
||||||
|
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.setCursor(186, 24);
|
||||||
|
//sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent);
|
||||||
|
if (useAMPM) tft.print(isAM ? "AM" : "PM");
|
||||||
|
//else tft.print(lineBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
|
|
||||||
@ -57,6 +139,9 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
*/
|
*/
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
PinManagerPinType pins[] = { { TFT_MOSI, true }, { TFT_MISO, false}, { TFT_SCLK, true }, { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
||||||
|
if (!pinManager.allocateMultiplePins(pins, 5, PinOwner::UM_FourLineDisplay)) { return; }
|
||||||
|
|
||||||
tft.init();
|
tft.init();
|
||||||
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
|
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
|
||||||
tft.fillScreen(TFT_BLACK);
|
tft.fillScreen(TFT_BLACK);
|
||||||
@ -65,10 +150,10 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
tft.setTextDatum(MC_DATUM);
|
tft.setTextDatum(MC_DATUM);
|
||||||
tft.setTextSize(2);
|
tft.setTextSize(2);
|
||||||
tft.print("Loading...");
|
tft.print("Loading...");
|
||||||
if (TFT_BL > 0)
|
if (TFT_BL >= 0)
|
||||||
{ // TFT_BL has been set in the TFT_eSPI library
|
{
|
||||||
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
|
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
|
||||||
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
|
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,174 +176,189 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
* Instead, use a timer check as shown here.
|
* Instead, use a timer check as shown here.
|
||||||
*/
|
*/
|
||||||
void loop() {
|
void loop() {
|
||||||
// Check if we time interval for redrawing passes.
|
char buff[LINE_BUFFER_SIZE];
|
||||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS)
|
|
||||||
|
// Check if we time interval for redrawing passes.
|
||||||
|
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastUpdate = millis();
|
lastUpdate = millis();
|
||||||
|
|
||||||
// Turn off display after 5 minutes with no change.
|
// Turn off display after 5 minutes with no change.
|
||||||
if(!displayTurnedOff && millis() - lastRedraw > 5*60*1000)
|
if (!displayTurnedOff && millis() - lastRedraw > 5*60*1000)
|
||||||
{
|
{
|
||||||
digitalWrite(TFT_BL, LOW); // Turn backlight off.
|
if (TFT_BL >= 0) digitalWrite(TFT_BL, LOW); // Turn backlight off.
|
||||||
displayTurnedOff = true;
|
displayTurnedOff = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if values which are shown on display changed from the last time.
|
// Check if values which are shown on display changed from the last time.
|
||||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid)
|
if ((((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) ||
|
||||||
{
|
(knownIp != (apActive ? IPAddress(4, 3, 2, 1) : Network.localIP())) ||
|
||||||
needRedraw = true;
|
(knownBrightness != bri) ||
|
||||||
}
|
(knownEffectSpeed != effectSpeed) ||
|
||||||
else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP()))
|
(knownEffectIntensity != effectIntensity) ||
|
||||||
{
|
(knownMode != strip.getMode()) ||
|
||||||
needRedraw = true;
|
(knownPalette != strip.getSegment(0).palette))
|
||||||
}
|
|
||||||
else if (knownBrightness != bri)
|
|
||||||
{
|
|
||||||
needRedraw = true;
|
|
||||||
}
|
|
||||||
else if (knownMode != strip.getMode())
|
|
||||||
{
|
|
||||||
needRedraw = true;
|
|
||||||
}
|
|
||||||
else if (knownPalette != strip.getSegment(0).palette)
|
|
||||||
{
|
|
||||||
needRedraw = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needRedraw)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
needRedraw = false;
|
|
||||||
|
|
||||||
if (displayTurnedOff)
|
|
||||||
{
|
|
||||||
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on.
|
|
||||||
displayTurnedOff = false;
|
|
||||||
}
|
|
||||||
lastRedraw = millis();
|
|
||||||
|
|
||||||
// Update last known values.
|
|
||||||
#if defined(ESP8266)
|
|
||||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
|
||||||
#else
|
|
||||||
knownSsid = WiFi.SSID();
|
|
||||||
#endif
|
|
||||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
|
||||||
knownBrightness = bri;
|
|
||||||
knownMode = strip.getMode();
|
|
||||||
knownPalette = strip.getSegment(0).palette;
|
|
||||||
|
|
||||||
tft.fillScreen(TFT_BLACK);
|
|
||||||
tft.setTextSize(2);
|
|
||||||
// First row with Wifi name
|
|
||||||
tft.setTextColor(TFT_SILVER);
|
|
||||||
tft.setCursor(3, 40);
|
|
||||||
tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0));
|
|
||||||
// Print `~` char to indicate that SSID is longer, than our dicplay
|
|
||||||
if (knownSsid.length() > tftcharwidth)
|
|
||||||
tft.print("~");
|
|
||||||
|
|
||||||
// Second row with AP IP and Password or IP
|
|
||||||
tft.setTextColor(TFT_GREEN);
|
|
||||||
tft.setTextSize(2);
|
|
||||||
tft.setCursor(3, 64);
|
|
||||||
// Print AP IP and password in AP mode or knownIP if AP not active.
|
|
||||||
|
|
||||||
if (apActive)
|
|
||||||
{
|
|
||||||
tft.setTextColor(TFT_YELLOW);
|
|
||||||
tft.print("AP IP: ");
|
|
||||||
tft.print(knownIp);
|
|
||||||
tft.setCursor(3,86);
|
|
||||||
tft.setTextColor(TFT_YELLOW);
|
|
||||||
tft.print("AP Pass:");
|
|
||||||
tft.print(apPass);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tft.setTextColor(TFT_GREEN);
|
|
||||||
tft.print("IP: ");
|
|
||||||
tft.print(knownIp);
|
|
||||||
tft.setCursor(3,86);
|
|
||||||
//tft.print("Signal Strength: ");
|
|
||||||
//tft.print(i.wifi.signal);
|
|
||||||
tft.setTextColor(TFT_WHITE);
|
|
||||||
tft.print("Bri: ");
|
|
||||||
tft.print(((float(bri)/255)*100),0);
|
|
||||||
tft.print("%");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Third row with mode name
|
|
||||||
tft.setCursor(3, 108);
|
|
||||||
uint8_t qComma = 0;
|
|
||||||
bool insideQuotes = false;
|
|
||||||
uint8_t printedChars = 0;
|
|
||||||
char singleJsonSymbol;
|
|
||||||
// Find the mode name in JSON
|
|
||||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++)
|
|
||||||
{
|
|
||||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
|
||||||
switch (singleJsonSymbol)
|
|
||||||
{
|
{
|
||||||
|
needRedraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needRedraw)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
needRedraw = false;
|
||||||
|
|
||||||
|
if (displayTurnedOff)
|
||||||
|
{
|
||||||
|
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
|
||||||
|
displayTurnedOff = false;
|
||||||
|
}
|
||||||
|
lastRedraw = millis();
|
||||||
|
|
||||||
|
// Update last known values.
|
||||||
|
#if defined(ESP8266)
|
||||||
|
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||||
|
#else
|
||||||
|
knownSsid = WiFi.SSID();
|
||||||
|
#endif
|
||||||
|
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||||
|
knownBrightness = bri;
|
||||||
|
knownMode = strip.getMode();
|
||||||
|
knownPalette = strip.getSegment(0).palette;
|
||||||
|
knownEffectSpeed = effectSpeed;
|
||||||
|
knownEffectIntensity = effectIntensity;
|
||||||
|
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
showTime();
|
||||||
|
|
||||||
|
tft.setTextSize(2);
|
||||||
|
|
||||||
|
// Wifi name
|
||||||
|
tft.setTextColor(TFT_GREEN);
|
||||||
|
tft.setCursor(0, 60);
|
||||||
|
String line = knownSsid.substring(0, tftcharwidth-1);
|
||||||
|
// Print `~` char to indicate that SSID is longer, than our display
|
||||||
|
if (knownSsid.length() > tftcharwidth) line = line.substring(0, tftcharwidth-1) + '~';
|
||||||
|
center(line, tftcharwidth);
|
||||||
|
tft.print(line.c_str());
|
||||||
|
|
||||||
|
// Print AP IP and password in AP mode or knownIP if AP not active.
|
||||||
|
if (apActive)
|
||||||
|
{
|
||||||
|
tft.setCursor(0, 84);
|
||||||
|
tft.print("AP IP: ");
|
||||||
|
tft.print(knownIp);
|
||||||
|
tft.setCursor(0,108);
|
||||||
|
tft.print("AP Pass:");
|
||||||
|
tft.print(apPass);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tft.setCursor(0, 84);
|
||||||
|
line = knownIp.toString();
|
||||||
|
center(line, tftcharwidth);
|
||||||
|
tft.print(line.c_str());
|
||||||
|
// percent brightness
|
||||||
|
tft.setCursor(0, 120);
|
||||||
|
tft.setTextColor(TFT_WHITE);
|
||||||
|
tft.print("Bri: ");
|
||||||
|
tft.print((((int)bri*100)/255));
|
||||||
|
tft.print("%");
|
||||||
|
// signal quality
|
||||||
|
tft.setCursor(124,120);
|
||||||
|
tft.print("Sig: ");
|
||||||
|
if (getSignalQuality(WiFi.RSSI()) < 10) {
|
||||||
|
tft.setTextColor(TFT_RED);
|
||||||
|
} else if (getSignalQuality(WiFi.RSSI()) < 25) {
|
||||||
|
tft.setTextColor(TFT_ORANGE);
|
||||||
|
} else {
|
||||||
|
tft.setTextColor(TFT_GREEN);
|
||||||
|
}
|
||||||
|
tft.print(getSignalQuality(WiFi.RSSI()));
|
||||||
|
tft.setTextColor(TFT_WHITE);
|
||||||
|
tft.print("%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// mode name
|
||||||
|
tft.setTextColor(TFT_CYAN);
|
||||||
|
tft.setCursor(0, 144);
|
||||||
|
uint8_t qComma = 0;
|
||||||
|
bool insideQuotes = false;
|
||||||
|
uint8_t printedChars = 0;
|
||||||
|
char singleJsonSymbol;
|
||||||
|
// Find the mode name in JSON
|
||||||
|
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++)
|
||||||
|
{
|
||||||
|
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||||
|
switch (singleJsonSymbol)
|
||||||
|
{
|
||||||
|
case '"':
|
||||||
|
insideQuotes = !insideQuotes;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
qComma++;
|
||||||
|
default:
|
||||||
|
if (!insideQuotes || (qComma != knownMode))
|
||||||
|
break;
|
||||||
|
tft.print(singleJsonSymbol);
|
||||||
|
printedChars++;
|
||||||
|
}
|
||||||
|
if ((qComma > knownMode) || (printedChars > tftcharwidth - 1))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// palette name
|
||||||
|
tft.setTextColor(TFT_YELLOW);
|
||||||
|
tft.setCursor(0, 168);
|
||||||
|
qComma = 0;
|
||||||
|
insideQuotes = false;
|
||||||
|
printedChars = 0;
|
||||||
|
// Looking for palette name in JSON.
|
||||||
|
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++)
|
||||||
|
{
|
||||||
|
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||||
|
switch (singleJsonSymbol)
|
||||||
|
{
|
||||||
case '"':
|
case '"':
|
||||||
insideQuotes = !insideQuotes;
|
insideQuotes = !insideQuotes;
|
||||||
break;
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
qComma++;
|
|
||||||
default:
|
|
||||||
if (!insideQuotes || (qComma != knownMode))
|
|
||||||
break;
|
break;
|
||||||
tft.setTextColor(TFT_MAGENTA);
|
case '[':
|
||||||
tft.print(singleJsonSymbol);
|
case ']':
|
||||||
printedChars++;
|
|
||||||
}
|
|
||||||
if ((qComma > knownMode) || (printedChars > tftcharwidth - 1))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Fourth row with palette name
|
|
||||||
tft.setTextColor(TFT_YELLOW);
|
|
||||||
tft.setCursor(3, 130);
|
|
||||||
qComma = 0;
|
|
||||||
insideQuotes = false;
|
|
||||||
printedChars = 0;
|
|
||||||
// Looking for palette name in JSON.
|
|
||||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++)
|
|
||||||
{
|
|
||||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
|
||||||
switch (singleJsonSymbol)
|
|
||||||
{
|
|
||||||
case '"':
|
|
||||||
insideQuotes = !insideQuotes;
|
|
||||||
break;
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
qComma++;
|
|
||||||
default:
|
|
||||||
if (!insideQuotes || (qComma != knownPalette))
|
|
||||||
break;
|
break;
|
||||||
tft.print(singleJsonSymbol);
|
case ',':
|
||||||
printedChars++;
|
qComma++;
|
||||||
|
default:
|
||||||
|
if (!insideQuotes || (qComma != knownPalette))
|
||||||
|
break;
|
||||||
|
tft.print(singleJsonSymbol);
|
||||||
|
printedChars++;
|
||||||
|
}
|
||||||
|
// The following is modified from the code from the u8g2/u8g8 based code (knownPalette was knownMode)
|
||||||
|
if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// The following is modified from the code from the u8g2/u8g8 based code (knownPalette was knownMode)
|
|
||||||
if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1))
|
tft.setCursor(0, 192);
|
||||||
break;
|
tft.setTextColor(TFT_SILVER);
|
||||||
}
|
sprintf_P(buff, PSTR("FX Spd:%3d Int:%3d"), effectSpeed, effectIntensity);
|
||||||
// Fifth row with estimated mA usage
|
tft.print(buff);
|
||||||
tft.setTextColor(TFT_SILVER);
|
|
||||||
tft.setCursor(3, 152);
|
// Fifth row with estimated mA usage
|
||||||
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
|
tft.setTextColor(TFT_SILVER);
|
||||||
tft.print("Current: ");
|
tft.setCursor(0, 216);
|
||||||
tft.print(strip.currentMilliamps);
|
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
|
||||||
tft.print("mA");
|
tft.print("Current: ");
|
||||||
|
tft.setTextColor(TFT_ORANGE);
|
||||||
|
tft.print(strip.currentMilliamps);
|
||||||
|
tft.print("mA");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||||
@ -295,7 +395,7 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject& root)
|
void readFromJsonState(JsonObject& root)
|
||||||
{
|
{
|
||||||
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,8 +416,8 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject& root)
|
void addToConfig(JsonObject& root)
|
||||||
{
|
{
|
||||||
JsonObject top = root.createNestedObject("exampleUsermod");
|
//JsonObject top = root.createNestedObject("exampleUsermod");
|
||||||
top["great"] = userVar0; //save this var persistently whenever settings are saved
|
//top["great"] = userVar0; //save this var persistently whenever settings are saved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -329,10 +429,11 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||||
*/
|
*/
|
||||||
void readFromConfig(JsonObject& root)
|
bool readFromConfig(JsonObject& root)
|
||||||
{
|
{
|
||||||
JsonObject top = root["top"];
|
//JsonObject top = root["top"];
|
||||||
userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
|
//userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -342,7 +443,7 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
*/
|
*/
|
||||||
uint16_t getId()
|
uint16_t getId()
|
||||||
{
|
{
|
||||||
return USERMOD_ST7789_DISPLAY;
|
return USERMOD_ID_ST7789_DISPLAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
//More methods can be added in the future, this example will then be extended.
|
//More methods can be added in the future, this example will then be extended.
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
// Setup for the ESP32 board with 1.5" 240x240 display
|
|
||||||
|
|
||||||
// See SetupX_Template.h for all options available
|
|
||||||
|
|
||||||
#define ST7789_DRIVER
|
|
||||||
#define TFT_SDA_READ // Display has a bidirectionsl SDA pin
|
|
||||||
|
|
||||||
#define TFT_WIDTH 240
|
|
||||||
#define TFT_HEIGHT 240
|
|
||||||
|
|
||||||
#define CGRAM_OFFSET // Library will add offsets required
|
|
||||||
|
|
||||||
//#define TFT_MISO -1
|
|
||||||
|
|
||||||
#define TFT_MOSI 21
|
|
||||||
#define TFT_SCLK 22
|
|
||||||
//#define TFT_CS 5
|
|
||||||
#define TFT_DC 18
|
|
||||||
#define TFT_RST 5
|
|
||||||
|
|
||||||
#define TFT_BL 26 // Display backlight control pin
|
|
||||||
|
|
||||||
#define TFT_BACKLIGHT_ON HIGH // HIGH or LOW are options
|
|
||||||
|
|
||||||
#define LOAD_GLCD
|
|
||||||
#define LOAD_FONT2
|
|
||||||
#define LOAD_FONT4
|
|
||||||
#define LOAD_FONT6
|
|
||||||
#define LOAD_FONT7
|
|
||||||
#define LOAD_FONT8
|
|
||||||
#define LOAD_GFXFF
|
|
||||||
|
|
||||||
//#define SMOOTH_FONT
|
|
||||||
|
|
||||||
//#define SPI_FREQUENCY 27000000
|
|
||||||
#define SPI_FREQUENCY 40000000 // Maximum for ILI9341
|
|
||||||
|
|
||||||
|
|
||||||
#define SPI_READ_FREQUENCY 6000000 // 6 MHz is the maximum SPI read speed for the ST7789V
|
|
@ -81,7 +81,9 @@ class UsermodTemperature : public Usermod {
|
|||||||
temperature = readDallas();
|
temperature = readDallas();
|
||||||
lastMeasurement = millis();
|
lastMeasurement = millis();
|
||||||
waitingForConversion = false;
|
waitingForConversion = false;
|
||||||
DEBUG_PRINTF("Read temperature %2.1f.\n", temperature);
|
//DEBUG_PRINTF("Read temperature %2.1f.\n", temperature); // does not work properly on 8266
|
||||||
|
DEBUG_PRINT(F("Read temperature "));
|
||||||
|
DEBUG_PRINTLN(temperature);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findSensor() {
|
bool findSensor() {
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
WLED v2 UserMod for running macros at sunrise and sunset.
|
|
||||||
|
|
||||||
At the time of this text, this user mod requires code to be changed to set certain variables:
|
|
||||||
1. To reflect the user's graphical location (latitude/longitude) used for calculating apparent sunrise/sunset
|
|
||||||
2. To specify which macros will be run at sunrise and/or sunset. (defaults to 15 at sunrise and 16 at sunset)
|
|
||||||
3. To optionally provide an offset from sunrise/sunset, in minutes (max of +/- 2 hours), when the macro will be run.
|
|
||||||
|
|
||||||
In addition, WLED must be configured to get time from NTP (and the time must be retrieved via NTP.)
|
|
||||||
|
|
||||||
Please open the UserMod_SunRiseAndSet.h file for instructions on what needs to be changed, where to copy files, etc.
|
|
||||||
|
|
||||||
If this usermod proves useful enough, the code might eventually be updated to allow prompting for the required information
|
|
||||||
via the web interface and to store settings in EEPROM instead of hard-coding in the .h file.
|
|
||||||
|
|
||||||
This usermod has only been tested on the esp32dev platform, but there's no reason it wouldn't work on other platforms.
|
|
@ -1,166 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "wled.h"
|
|
||||||
#include <Dusk2Dawn.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* REQUIREMENTS:
|
|
||||||
* The Dusk2Dawn library must be installed. This can be found at https://github.com/dmkishi/Dusk2Dawn. The 1.0.1 version of this library found via
|
|
||||||
* Arduino or platformio library managers is buggy and won't compile. The latest version from github should be used.
|
|
||||||
*
|
|
||||||
* NTP must be enabled and functional. It simply makes no sense to have events on sunrise/sunset when an accurate time isn't available.
|
|
||||||
*
|
|
||||||
* The user's geographical latitude and longitude must be configured (in decimal, not degrees/minutes/etc) using m_fLatitude and m_fLongitude
|
|
||||||
*
|
|
||||||
* if desired, an offset of up to +/- 2 hours can be specified for each of sunrise/sunset using m_sunriseOffset and m_sunsetOffset (defaults to 0)
|
|
||||||
*
|
|
||||||
* The specific macro to run at sunrise and/or sunset can be changed using m_sunriseMacro and m_sunsetMacro. (defaults to 15 and 16)
|
|
||||||
*
|
|
||||||
* From the Dusk2Dawn library:
|
|
||||||
* HINT: An easy way to find the longitude and latitude for any location is
|
|
||||||
* to find the spot in Google Maps, right click the place on the map, and
|
|
||||||
* select "What's here?". At the bottom, you’ll see a card with the
|
|
||||||
* coordinates.
|
|
||||||
*
|
|
||||||
* Once configured, copy UserMod_SunRiseAndSet.h to the sketch file (the same folder as wled00.ino exists),
|
|
||||||
* and then edit "usermods_list.cpp":
|
|
||||||
* Add '#include "UserMod_SunRiseAndSet.h"' in the 'includes' area
|
|
||||||
* Add 'usermods.add(new UserMod_SunRiseAndSet());' in the registerUsermods() area
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class UserMod_SunRiseAndSet : public Usermod
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
/**** USER SETTINGS ****/
|
|
||||||
|
|
||||||
float m_fLatitude = 40.6; // latitude where sunrise/set are calculated
|
|
||||||
float m_fLongitude = -79.80; // longitude where sunrise/set are calculated
|
|
||||||
int8_t m_sunriseOffset = 0; // offset from sunrise, in minutes, when macro should be run (negative for before sunrise, positive for after sunrise)
|
|
||||||
int8_t m_sunsetOffset = 0; // offset from sunset, in minutes, when macro should be run (negative for before sunset, positive for after sunset)
|
|
||||||
uint8_t m_sunriseMacro = 15; // macro number to run at sunrise
|
|
||||||
uint8_t m_sunsetMacro = 16; // macro number to run at sunset
|
|
||||||
|
|
||||||
/**** END OF USER SETTINGS. DO NOT EDIT BELOW THIS LINE! ****/
|
|
||||||
|
|
||||||
|
|
||||||
Dusk2Dawn *m_pD2D = NULL; // this must be dynamically allocated in order for parameters to be loaded from EEPROM
|
|
||||||
|
|
||||||
int m_nUserSunrise = -1; // time, in minutes from midnight, of sunrise
|
|
||||||
int m_nUserSunset = -1; // time, in minutes from midnight, of sunset
|
|
||||||
|
|
||||||
byte m_nLastRunMinute = -1; // indicates what minute the userloop was last run - used so that the code only runs once per minute
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual void setup(void)
|
|
||||||
{
|
|
||||||
/* TODO: From EEPROM, load the following variables:
|
|
||||||
*
|
|
||||||
* int16_t latitude16 = 4060; // user provided latitude, multiplied by 100 and rounded
|
|
||||||
* int16_t longitude16 = -7980; // user provided longitude, multiplied by 100 and rounded.
|
|
||||||
* int8_t sunrise_offset = 0; // number of minutes to offset the sunrise macro trigger (positive for minutes after sunrise, negative for minutes before)
|
|
||||||
* int8_t sunset_offset = 0; // number of minutes to offset the sunset macro trigger (positive for minutes after sunset, negative for minutes before)
|
|
||||||
*
|
|
||||||
* then:
|
|
||||||
* m_fLatitude = (float)latitude / 100.0;
|
|
||||||
* m_fLongitude = (float)longitude / 100.0;
|
|
||||||
* m_sunriseOffset = sunrise_offset;
|
|
||||||
* m_sunsetOffset = sunset_offset;
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ((0.0 != m_fLatitude) || (0.0 != m_fLongitude))
|
|
||||||
{
|
|
||||||
m_pD2D = new Dusk2Dawn (m_fLatitude, m_fLongitude, 0 /* UTC */);
|
|
||||||
// can't really check for failures. if the alloc fails, the mod just doesn't work.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(void)
|
|
||||||
{
|
|
||||||
// without NTP, or a configured lat/long, none of this stuff is going to work...
|
|
||||||
// As an alternative, need to figure out how to determine if the user has manually set the clock or not.
|
|
||||||
if (m_pD2D && (999000000L != ntpLastSyncTime))
|
|
||||||
{
|
|
||||||
// to prevent needing to import all the timezone stuff from other modules, work completely in UTC
|
|
||||||
time_t timeUTC = toki.second();
|
|
||||||
tmElements_t tmNow;
|
|
||||||
breakTime(timeUTC, tmNow);
|
|
||||||
int nCurMinute = tmNow.Minute;
|
|
||||||
|
|
||||||
if (m_nLastRunMinute != nCurMinute) //only check once a new minute begins
|
|
||||||
{
|
|
||||||
m_nLastRunMinute = nCurMinute;
|
|
||||||
int numMinutes = (60 * tmNow.Hour) + m_nLastRunMinute; // how many minutes into the day are we?
|
|
||||||
|
|
||||||
// check to see if sunrise/sunset should be re-determined. Only do this if neither sunrise nor sunset
|
|
||||||
// are set. That happens when the device has just stated, and after both sunrise/sunset have already run.
|
|
||||||
if ((-1 == m_nUserSunrise) && (-1 == m_nUserSunset))
|
|
||||||
{
|
|
||||||
m_nUserSunrise = m_pD2D->sunrise(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
|
||||||
m_nUserSunset = m_pD2D->sunset(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
|
||||||
if (m_nUserSunrise > numMinutes) // has sunrise already passed? if so, recompute for tomorrow
|
|
||||||
{
|
|
||||||
breakTime(timeUTC + (60*60*24), tmNow);
|
|
||||||
m_nUserSunrise = m_pD2D->sunrise(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
|
||||||
if (m_nUserSunset > numMinutes) // if sunset has also passed, recompute that as well
|
|
||||||
{
|
|
||||||
m_nUserSunset = m_pD2D->sunset(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// offset by user provided values. becuase the offsets are signed bytes, the max offset is just over 2 hours.
|
|
||||||
m_nUserSunrise += m_sunriseOffset;
|
|
||||||
m_nUserSunset += m_sunsetOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numMinutes == m_nUserSunrise) // Good Morning!
|
|
||||||
{
|
|
||||||
if (m_sunriseMacro)
|
|
||||||
applyMacro(m_sunriseMacro); // run macro 15
|
|
||||||
m_nUserSunrise = -1;
|
|
||||||
}
|
|
||||||
else if (numMinutes == m_nUserSunset) // Good Night!
|
|
||||||
{
|
|
||||||
if (m_sunsetMacro)
|
|
||||||
applyMacro(m_sunsetMacro); // run macro 16
|
|
||||||
m_nUserSunset = -1;
|
|
||||||
}
|
|
||||||
} // if (m_nLastRunMinute != nCurMinute)
|
|
||||||
} // if (m_pD2D && (999000000L != ntpLastSyncTime))
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToJsonState(JsonObject& root)
|
|
||||||
{
|
|
||||||
JsonObject user = root["SunRiseAndSet"];
|
|
||||||
if (user.isNull()) user = root.createNestedObject("SunRiseAndSet");
|
|
||||||
|
|
||||||
char buf[10];
|
|
||||||
if (-1 != m_nUserSunrise)
|
|
||||||
{
|
|
||||||
snprintf(buf, 10, "%02d:%02d UTC", m_nUserSunrise / 60, m_nUserSunrise % 60);
|
|
||||||
user["rise"] = buf;
|
|
||||||
}
|
|
||||||
if (-1 != m_nUserSunset)
|
|
||||||
{
|
|
||||||
snprintf(buf, 10, "%02d:%02d UTC", m_nUserSunset / 60, m_nUserSunset % 60);
|
|
||||||
user["set"] = buf;
|
|
||||||
}
|
|
||||||
JsonObject vars = user.createNestedObject("vars");
|
|
||||||
vars["lat"] = m_fLatitude;
|
|
||||||
vars["long"] = m_fLongitude;
|
|
||||||
vars["rise_mac"] = m_sunriseMacro;
|
|
||||||
vars["set_mac"] = m_sunsetMacro;
|
|
||||||
vars["rise_off"] = m_sunriseOffset;
|
|
||||||
vars["set_off"] = m_sunsetOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
~UserMod_SunRiseAndSet(void)
|
|
||||||
{
|
|
||||||
if (m_pD2D) delete m_pD2D;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,515 +0,0 @@
|
|||||||
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
|
|
||||||
#ifndef NpbWrapper_h
|
|
||||||
#define NpbWrapper_h
|
|
||||||
|
|
||||||
// make sure we're using esp32 platform
|
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
|
||||||
#error This version of NbpWrapper.h only works with ESP32 hardware.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NUM_STRIPS
|
|
||||||
#error Need to define number of LED strips using build flag -D NUM_STRIPS=4 for 4 LED strips
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PIXEL_COUNTS
|
|
||||||
#error Need to define pixel counts using build flag -D PIXEL_COUNTS="25, 25, 25, 25" for 4 LED strips with 25 LEDs each
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DATA_PINS
|
|
||||||
#error Need to define data pins using build flag -D DATA_PINS="1, 2, 3, 4" if LED strips are on data pins 1, 2, 3, and 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// //PIN CONFIGURATION
|
|
||||||
#ifndef LEDPIN
|
|
||||||
#define LEDPIN 1 // Legacy pin def required by some other portions of code. This pin is not used do drive LEDs.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef IRPIN
|
|
||||||
#define IRPIN -1 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RLYPIN
|
|
||||||
#define RLYPIN -1 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef AUXPIN
|
|
||||||
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RLYMDE
|
|
||||||
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <NeoPixelBrightnessBus.h>
|
|
||||||
#include "const.h"
|
|
||||||
|
|
||||||
const uint8_t numStrips = NUM_STRIPS; // max 8 strips allowed on esp32
|
|
||||||
const uint16_t pixelCounts[numStrips] = {PIXEL_COUNTS}; // number of pixels on each strip
|
|
||||||
const uint8_t dataPins[numStrips] = {DATA_PINS}; // change these pins based on your board
|
|
||||||
|
|
||||||
#define PIXELFEATURE3 NeoGrbFeature
|
|
||||||
#define PIXELFEATURE4 NeoGrbwFeature
|
|
||||||
|
|
||||||
// ESP32 has 8 RMT interfaces available, each of which can drive a strip of pixels
|
|
||||||
// Convenience #defines for creating NeoPixelBrightnessBus on each RMT interface for both GRB and GRBW LED strips
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt0 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt0Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt1 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt1Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt2 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt2Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt3 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt3Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt4 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt4Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt5 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt5Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt6 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt6Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbRmt7 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt7Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt0 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt0Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt1 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt1Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt2 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt2Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt3 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt3Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt4 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt4Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt5 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt5Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt6 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt6Ws2812xMethod>
|
|
||||||
#define NeoPixelBrightnessBusGrbwRmt7 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt7Ws2812xMethod>
|
|
||||||
|
|
||||||
enum NeoPixelType
|
|
||||||
{
|
|
||||||
NeoPixelType_None = 0,
|
|
||||||
NeoPixelType_Grb = 1,
|
|
||||||
NeoPixelType_Grbw = 2,
|
|
||||||
NeoPixelType_End = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
class NeoPixelWrapper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NeoPixelWrapper() :
|
|
||||||
_type(NeoPixelType_None)
|
|
||||||
{
|
|
||||||
// On initialization fill in the pixelStripStartIdx array with the beginning index of each strip
|
|
||||||
// relative to th entire array.
|
|
||||||
uint16_t totalPixels = 0;
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
pixelStripStartIdx[idx] = totalPixels;
|
|
||||||
totalPixels += pixelCounts[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~NeoPixelWrapper()
|
|
||||||
{
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Begin(NeoPixelType type, uint16_t pixelCount)
|
|
||||||
{
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
|
|
||||||
_type = type;
|
|
||||||
|
|
||||||
switch (_type)
|
|
||||||
{
|
|
||||||
case NeoPixelType_Grb:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: pGrb0 = new NeoPixelBrightnessBusGrbRmt0(pixelCounts[idx], dataPins[idx]); pGrb0->Begin(); break;
|
|
||||||
case 1: pGrb1 = new NeoPixelBrightnessBusGrbRmt1(pixelCounts[idx], dataPins[idx]); pGrb1->Begin(); break;
|
|
||||||
case 2: pGrb2 = new NeoPixelBrightnessBusGrbRmt2(pixelCounts[idx], dataPins[idx]); pGrb2->Begin(); break;
|
|
||||||
case 3: pGrb3 = new NeoPixelBrightnessBusGrbRmt3(pixelCounts[idx], dataPins[idx]); pGrb3->Begin(); break;
|
|
||||||
case 4: pGrb4 = new NeoPixelBrightnessBusGrbRmt4(pixelCounts[idx], dataPins[idx]); pGrb4->Begin(); break;
|
|
||||||
case 5: pGrb5 = new NeoPixelBrightnessBusGrbRmt5(pixelCounts[idx], dataPins[idx]); pGrb5->Begin(); break;
|
|
||||||
case 6: pGrb6 = new NeoPixelBrightnessBusGrbRmt6(pixelCounts[idx], dataPins[idx]); pGrb6->Begin(); break;
|
|
||||||
case 7: pGrb7 = new NeoPixelBrightnessBusGrbRmt7(pixelCounts[idx], dataPins[idx]); pGrb7->Begin(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NeoPixelType_Grbw:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: pGrbw0 = new NeoPixelBrightnessBusGrbwRmt0(pixelCounts[idx], dataPins[idx]); pGrbw0->Begin(); break;
|
|
||||||
case 1: pGrbw1 = new NeoPixelBrightnessBusGrbwRmt1(pixelCounts[idx], dataPins[idx]); pGrbw1->Begin(); break;
|
|
||||||
case 2: pGrbw2 = new NeoPixelBrightnessBusGrbwRmt2(pixelCounts[idx], dataPins[idx]); pGrbw2->Begin(); break;
|
|
||||||
case 3: pGrbw3 = new NeoPixelBrightnessBusGrbwRmt3(pixelCounts[idx], dataPins[idx]); pGrbw3->Begin(); break;
|
|
||||||
case 4: pGrbw4 = new NeoPixelBrightnessBusGrbwRmt4(pixelCounts[idx], dataPins[idx]); pGrbw4->Begin(); break;
|
|
||||||
case 5: pGrbw5 = new NeoPixelBrightnessBusGrbwRmt5(pixelCounts[idx], dataPins[idx]); pGrbw5->Begin(); break;
|
|
||||||
case 6: pGrbw6 = new NeoPixelBrightnessBusGrbwRmt6(pixelCounts[idx], dataPins[idx]); pGrbw6->Begin(); break;
|
|
||||||
case 7: pGrbw7 = new NeoPixelBrightnessBusGrbwRmt7(pixelCounts[idx], dataPins[idx]); pGrbw7->Begin(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Show()
|
|
||||||
{
|
|
||||||
switch (_type)
|
|
||||||
{
|
|
||||||
case NeoPixelType_Grb:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: pGrb0->Show(); break;
|
|
||||||
case 1: pGrb1->Show(); break;
|
|
||||||
case 2: pGrb2->Show(); break;
|
|
||||||
case 3: pGrb3->Show(); break;
|
|
||||||
case 4: pGrb4->Show(); break;
|
|
||||||
case 5: pGrb5->Show(); break;
|
|
||||||
case 6: pGrb6->Show(); break;
|
|
||||||
case 7: pGrb7->Show(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NeoPixelType_Grbw:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: pGrbw0->Show(); break;
|
|
||||||
case 1: pGrbw1->Show(); break;
|
|
||||||
case 2: pGrbw2->Show(); break;
|
|
||||||
case 3: pGrbw3->Show(); break;
|
|
||||||
case 4: pGrbw4->Show(); break;
|
|
||||||
case 5: pGrbw5->Show(); break;
|
|
||||||
case 6: pGrbw6->Show(); break;
|
|
||||||
case 7: pGrbw7->Show(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CanShow()
|
|
||||||
{
|
|
||||||
bool canShow = true;
|
|
||||||
switch (_type)
|
|
||||||
{
|
|
||||||
case NeoPixelType_Grb:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: canShow &= pGrb0->CanShow(); break;
|
|
||||||
case 1: canShow &= pGrb1->CanShow(); break;
|
|
||||||
case 2: canShow &= pGrb2->CanShow(); break;
|
|
||||||
case 3: canShow &= pGrb3->CanShow(); break;
|
|
||||||
case 4: canShow &= pGrb4->CanShow(); break;
|
|
||||||
case 5: canShow &= pGrb5->CanShow(); break;
|
|
||||||
case 6: canShow &= pGrb6->CanShow(); break;
|
|
||||||
case 7: canShow &= pGrb7->CanShow(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NeoPixelType_Grbw:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: canShow &= pGrbw0->CanShow(); break;
|
|
||||||
case 1: canShow &= pGrbw1->CanShow(); break;
|
|
||||||
case 2: canShow &= pGrbw2->CanShow(); break;
|
|
||||||
case 3: canShow &= pGrbw3->CanShow(); break;
|
|
||||||
case 4: canShow &= pGrbw4->CanShow(); break;
|
|
||||||
case 5: canShow &= pGrbw5->CanShow(); break;
|
|
||||||
case 6: canShow &= pGrbw6->CanShow(); break;
|
|
||||||
case 7: canShow &= pGrbw7->CanShow(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return canShow;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPixelColorRaw(uint16_t indexPixel, RgbwColor c)
|
|
||||||
{
|
|
||||||
// figure out which strip this pixel index is on
|
|
||||||
uint8_t stripIdx = 0;
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
if (indexPixel >= pixelStripStartIdx[idx])
|
|
||||||
{
|
|
||||||
stripIdx = idx;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
|
||||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
|
||||||
switch (_type)
|
|
||||||
{
|
|
||||||
case NeoPixelType_Grb:
|
|
||||||
{
|
|
||||||
RgbColor rgb = RgbColor(c.R, c.G, c.B);
|
|
||||||
switch (stripIdx)
|
|
||||||
{
|
|
||||||
case 0: pGrb0->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
case 1: pGrb1->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
case 2: pGrb2->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
case 3: pGrb3->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
case 4: pGrb4->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
case 5: pGrb5->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
case 6: pGrb6->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
case 7: pGrb7->SetPixelColor(indexPixel, rgb); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NeoPixelType_Grbw:
|
|
||||||
{
|
|
||||||
switch (stripIdx)
|
|
||||||
{
|
|
||||||
case 0: pGrbw0->SetPixelColor(indexPixel, c); break;
|
|
||||||
case 1: pGrbw1->SetPixelColor(indexPixel, c); break;
|
|
||||||
case 2: pGrbw2->SetPixelColor(indexPixel, c); break;
|
|
||||||
case 3: pGrbw3->SetPixelColor(indexPixel, c); break;
|
|
||||||
case 4: pGrbw4->SetPixelColor(indexPixel, c); break;
|
|
||||||
case 5: pGrbw5->SetPixelColor(indexPixel, c); break;
|
|
||||||
case 6: pGrbw6->SetPixelColor(indexPixel, c); break;
|
|
||||||
case 7: pGrbw7->SetPixelColor(indexPixel, c); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPixelColor(uint16_t indexPixel, RgbwColor c)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Set pixel color with necessary color order conversion.
|
|
||||||
*/
|
|
||||||
|
|
||||||
RgbwColor col;
|
|
||||||
|
|
||||||
uint8_t co = _colorOrder;
|
|
||||||
#ifdef COLOR_ORDER_OVERRIDE
|
|
||||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//reorder channels to selected order
|
|
||||||
switch (co)
|
|
||||||
{
|
|
||||||
case 0: col.G = c.G; col.R = c.R; col.B = c.B; break; //0 = GRB, default
|
|
||||||
case 1: col.G = c.R; col.R = c.G; col.B = c.B; break; //1 = RGB, common for WS2811
|
|
||||||
case 2: col.G = c.B; col.R = c.R; col.B = c.G; break; //2 = BRG
|
|
||||||
case 3: col.G = c.R; col.R = c.B; col.B = c.G; break; //3 = RBG
|
|
||||||
case 4: col.G = c.B; col.R = c.G; col.B = c.R; break; //4 = BGR
|
|
||||||
default: col.G = c.G; col.R = c.B; col.B = c.R; break; //5 = GBR
|
|
||||||
}
|
|
||||||
col.W = c.W;
|
|
||||||
|
|
||||||
SetPixelColorRaw(indexPixel, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetBrightness(byte b)
|
|
||||||
{
|
|
||||||
switch (_type)
|
|
||||||
{
|
|
||||||
case NeoPixelType_Grb:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: pGrb0->SetBrightness(b); break;
|
|
||||||
case 1: pGrb1->SetBrightness(b); break;
|
|
||||||
case 2: pGrb2->SetBrightness(b); break;
|
|
||||||
case 3: pGrb3->SetBrightness(b); break;
|
|
||||||
case 4: pGrb4->SetBrightness(b); break;
|
|
||||||
case 5: pGrb5->SetBrightness(b); break;
|
|
||||||
case 6: pGrb6->SetBrightness(b); break;
|
|
||||||
case 7: pGrb7->SetBrightness(b); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NeoPixelType_Grbw:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: pGrbw0->SetBrightness(b); break;
|
|
||||||
case 1: pGrbw1->SetBrightness(b); break;
|
|
||||||
case 2: pGrbw2->SetBrightness(b); break;
|
|
||||||
case 3: pGrbw3->SetBrightness(b); break;
|
|
||||||
case 4: pGrbw4->SetBrightness(b); break;
|
|
||||||
case 5: pGrbw5->SetBrightness(b); break;
|
|
||||||
case 6: pGrbw6->SetBrightness(b); break;
|
|
||||||
case 7: pGrbw7->SetBrightness(b); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetColorOrder(byte colorOrder)
|
|
||||||
{
|
|
||||||
_colorOrder = colorOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetColorOrder()
|
|
||||||
{
|
|
||||||
return _colorOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
RgbwColor GetPixelColorRaw(uint16_t indexPixel) const
|
|
||||||
{
|
|
||||||
// figure out which strip this pixel index is on
|
|
||||||
uint8_t stripIdx = 0;
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
if (indexPixel >= pixelStripStartIdx[idx])
|
|
||||||
{
|
|
||||||
stripIdx = idx;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
|
||||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
|
||||||
switch (_type)
|
|
||||||
{
|
|
||||||
case NeoPixelType_Grb:
|
|
||||||
{
|
|
||||||
switch (stripIdx)
|
|
||||||
{
|
|
||||||
case 0: return pGrb0->GetPixelColor(indexPixel);
|
|
||||||
case 1: return pGrb1->GetPixelColor(indexPixel);
|
|
||||||
case 2: return pGrb2->GetPixelColor(indexPixel);
|
|
||||||
case 3: return pGrb3->GetPixelColor(indexPixel);
|
|
||||||
case 4: return pGrb4->GetPixelColor(indexPixel);
|
|
||||||
case 5: return pGrb5->GetPixelColor(indexPixel);
|
|
||||||
case 6: return pGrb6->GetPixelColor(indexPixel);
|
|
||||||
case 7: return pGrb7->GetPixelColor(indexPixel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NeoPixelType_Grbw:
|
|
||||||
switch (stripIdx)
|
|
||||||
{
|
|
||||||
case 0: return pGrbw0->GetPixelColor(indexPixel);
|
|
||||||
case 1: return pGrbw1->GetPixelColor(indexPixel);
|
|
||||||
case 2: return pGrbw2->GetPixelColor(indexPixel);
|
|
||||||
case 3: return pGrbw3->GetPixelColor(indexPixel);
|
|
||||||
case 4: return pGrbw4->GetPixelColor(indexPixel);
|
|
||||||
case 5: return pGrbw5->GetPixelColor(indexPixel);
|
|
||||||
case 6: return pGrbw6->GetPixelColor(indexPixel);
|
|
||||||
case 7: return pGrbw7->GetPixelColor(indexPixel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Due to feature differences, some support RGBW but the method name
|
|
||||||
// here needs to be unique, thus GetPixeColorRgbw
|
|
||||||
uint32_t GetPixelColorRgbw(uint16_t indexPixel) const
|
|
||||||
{
|
|
||||||
RgbwColor col = GetPixelColorRaw(indexPixel);
|
|
||||||
uint8_t co = _colorOrder;
|
|
||||||
#ifdef COLOR_ORDER_OVERRIDE
|
|
||||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (co)
|
|
||||||
{
|
|
||||||
// W G R B
|
|
||||||
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
|
|
||||||
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
|
|
||||||
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
|
|
||||||
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
|
|
||||||
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
|
|
||||||
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
NeoPixelType _type;
|
|
||||||
byte _colorOrder = 0;
|
|
||||||
|
|
||||||
uint16_t pixelStripStartIdx[numStrips];
|
|
||||||
|
|
||||||
// pointers for every possible type for up to 8 strips
|
|
||||||
NeoPixelBrightnessBusGrbRmt0 *pGrb0;
|
|
||||||
NeoPixelBrightnessBusGrbRmt1 *pGrb1;
|
|
||||||
NeoPixelBrightnessBusGrbRmt2 *pGrb2;
|
|
||||||
NeoPixelBrightnessBusGrbRmt3 *pGrb3;
|
|
||||||
NeoPixelBrightnessBusGrbRmt4 *pGrb4;
|
|
||||||
NeoPixelBrightnessBusGrbRmt5 *pGrb5;
|
|
||||||
NeoPixelBrightnessBusGrbRmt6 *pGrb6;
|
|
||||||
NeoPixelBrightnessBusGrbRmt7 *pGrb7;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt0 *pGrbw0;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt1 *pGrbw1;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt2 *pGrbw2;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt3 *pGrbw3;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt4 *pGrbw4;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt5 *pGrbw5;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt6 *pGrbw6;
|
|
||||||
NeoPixelBrightnessBusGrbwRmt7 *pGrbw7;
|
|
||||||
|
|
||||||
void cleanup()
|
|
||||||
{
|
|
||||||
switch (_type)
|
|
||||||
{
|
|
||||||
case NeoPixelType_Grb:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: delete pGrb0; pGrb0 = NULL; break;
|
|
||||||
case 1: delete pGrb1; pGrb1 = NULL; break;
|
|
||||||
case 2: delete pGrb2; pGrb2 = NULL; break;
|
|
||||||
case 3: delete pGrb3; pGrb3 = NULL; break;
|
|
||||||
case 4: delete pGrb4; pGrb4 = NULL; break;
|
|
||||||
case 5: delete pGrb5; pGrb5 = NULL; break;
|
|
||||||
case 6: delete pGrb6; pGrb6 = NULL; break;
|
|
||||||
case 7: delete pGrb7; pGrb7 = NULL; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NeoPixelType_Grbw:
|
|
||||||
{
|
|
||||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
|
||||||
{
|
|
||||||
switch (idx)
|
|
||||||
{
|
|
||||||
case 0: delete pGrbw0; pGrbw0 = NULL; break;
|
|
||||||
case 1: delete pGrbw1; pGrbw1 = NULL; break;
|
|
||||||
case 2: delete pGrbw2; pGrbw2 = NULL; break;
|
|
||||||
case 3: delete pGrbw3; pGrbw3 = NULL; break;
|
|
||||||
case 4: delete pGrbw4; pGrbw4 = NULL; break;
|
|
||||||
case 5: delete pGrbw5; pGrbw5 = NULL; break;
|
|
||||||
case 6: delete pGrbw6; pGrbw6 = NULL; break;
|
|
||||||
case 7: delete pGrbw7; pGrbw7 = NULL; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,22 +0,0 @@
|
|||||||
# esp32_multistrip
|
|
||||||
|
|
||||||
This usermod enables up to 8 data pins to be used from an esp32 module to drive separate LED strands. This only works with one-wire LEDs like the WS2812.
|
|
||||||
|
|
||||||
The esp32 RMT hardware is used for data output. See here for hardware driver implementation details: https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
|
||||||
|
|
||||||
Pass the following variables to the compiler as build flags:
|
|
||||||
|
|
||||||
- `ESP32_MULTISTRIP`
|
|
||||||
- Define this to use usermod NpbWrapper.h instead of default one in WLED.
|
|
||||||
- `NUM_STRIPS`
|
|
||||||
- Number of strips in use
|
|
||||||
- `PIXEL_COUNTS`
|
|
||||||
- List of pixel counts in each strip
|
|
||||||
- `DATA_PINS`
|
|
||||||
- List of data pins each strip is attached to. There may be board-specific restrictions on which pins can be used for RTM.
|
|
||||||
|
|
||||||
From the perspective of WLED software, the LEDs are addressed as one long strand. The modified NbpWrapper.h file addresses the appropriate strand from the overall LED index based on the number of LEDs defined in each strand.
|
|
||||||
|
|
||||||
See `platformio_override.ini` for example configuration.
|
|
||||||
|
|
||||||
Tested on low cost ESP-WROOM-32 dev boards from Amazon, such as those sold by KeeYees.
|
|
@ -1,16 +0,0 @@
|
|||||||
; Example platformio_override.ini that shows how to configure your environment to use the multistrip usermod.
|
|
||||||
; Copy this file to the base wled directory that contains platformio.ini.
|
|
||||||
; Multistrip requires ESP32 because it has many more pins that can be used as LED outputs.
|
|
||||||
; Need to define NUM_STRIPS, PIXEL_COUNTS, and DATA_PINS as shown below.
|
|
||||||
|
|
||||||
[platformio]
|
|
||||||
default_envs = esp32_multistrip
|
|
||||||
|
|
||||||
[env:esp32_multistrip]
|
|
||||||
extends=env:esp32dev
|
|
||||||
build_flags = ${env:esp32dev.build_flags}
|
|
||||||
-D ESP32_MULTISTRIP ; define this variable to use ESP32_MULTISTRIP usermod
|
|
||||||
-D NUM_STRIPS=4 ; number of pixel strips in use
|
|
||||||
-D PIXEL_COUNTS="50, 50, 50, 50" ; number of pixels in each strip
|
|
||||||
-D DATA_PINS="25, 26, 32, 33" ; esp32 pins used for each pixel strip. available pins depends on esp32 module.
|
|
||||||
|
|
@ -317,15 +317,15 @@ class MultiRelay : public Usermod {
|
|||||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
void addToJsonState(JsonObject &root) {
|
//void addToJsonState(JsonObject &root) {
|
||||||
}
|
//}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject &root) {
|
//void readFromJsonState(JsonObject &root) {
|
||||||
}
|
//}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provide the changeable values
|
* provide the changeable values
|
||||||
@ -335,11 +335,12 @@ class MultiRelay : public Usermod {
|
|||||||
|
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-";
|
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||||
top[parName+"pin"] = _relay[i].pin;
|
JsonObject relay = top.createNestedObject(parName);
|
||||||
top[parName+FPSTR(_activeHigh)] = _relay[i].mode;
|
relay["pin"] = _relay[i].pin;
|
||||||
top[parName+FPSTR(_delay_str)] = _relay[i].delay;
|
relay[FPSTR(_activeHigh)] = _relay[i].mode;
|
||||||
top[parName+FPSTR(_external)] = _relay[i].external;
|
relay[FPSTR(_delay_str)] = _relay[i].delay;
|
||||||
|
relay[FPSTR(_external)] = _relay[i].external;
|
||||||
}
|
}
|
||||||
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
||||||
}
|
}
|
||||||
@ -363,12 +364,19 @@ class MultiRelay : public Usermod {
|
|||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
|
|
||||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-";
|
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||||
oldPin[i] = _relay[i].pin;
|
oldPin[i] = _relay[i].pin;
|
||||||
|
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
|
||||||
|
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
|
||||||
|
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
||||||
|
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
||||||
|
// begin backwards compatibility (beta) remove when 0.13 is released
|
||||||
|
parName += '-';
|
||||||
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
||||||
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
||||||
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
||||||
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
||||||
|
// end compatibility
|
||||||
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
|
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +404,7 @@ class MultiRelay : public Usermod {
|
|||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return true;
|
return !top[F("relay-0")]["pin"].isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
# QuinLED-Dig-Quad Preassembled Unofficial Build
|
|
||||||
|
|
||||||
This usermod targets the [Preassembled QuinLED-Dig-Quad](https://quinled.info/pre-assembled-quinled-dig-quad/). Tested on board revision v1r6b,
|
|
||||||
and includes the following features:
|
|
||||||
|
|
||||||
* **Multi-channel Support** - enabling use of LED1, LED2, LED3, LED4 pins to work using segments
|
|
||||||
* **Temperature Sensor Support** - pulls readings from the built-in temperature sensor and adds the reading to the *Info* page in the UI
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
As a starting point, you should check out this awesome video from Quindor: [How to compile WLED yourself](https://quinled.info/2020/12/22/livestream-wled-compile/). The usermod you are reading now just provides some shortcuts for parts of what were covered in that video.
|
|
||||||
|
|
||||||
## Build Firmware with Multi-channel and Temp Support
|
|
||||||
|
|
||||||
1. Copy the `platformio_override.ini` file to the project's root directory
|
|
||||||
1. If using VS Code with the PlatformIO plugin like in the video, you will now see this new project task listed in the PLATFORMIO panel at the bottom as `env:QL-DigQuad-Pre-v0.1` (you probably need to hit the refresh button)
|
|
||||||
|
|
||||||
<img src="images/pio-screenshot.png" width="400px"/>
|
|
||||||
|
|
||||||
1. Edit this file from the root directory as needed:
|
|
||||||
|
|
||||||
<img src="images/params.png" width="400px"/>
|
|
||||||
|
|
||||||
* `PIXEL_COUNTS` may need to be adjusted for your set-up. E.g. I have lots of LEDs in Channel 1, but that's probably unusual for most
|
|
||||||
* `DATA_PINS` may need to be changed to "16,3,1,26" instead of "16,1,3,26" apparently depending on the board revision or some such
|
|
||||||
|
|
||||||
1. Build the mod (e.g. click `Build` from the project task circled above) and update your firmware using the `QL-DigQuad-Pre-v0.1` file, e.g. using _Manual OTA_ from the Config menu. Based on the video and my own experience, you might need to build twice 🤷♂️.
|
|
||||||
|
|
||||||
## Observing Temperature
|
|
||||||
|
|
||||||
Hopefully you can now see the Temperature listed in the Info page. If not, use Chrome Developer Tools to find the current temperature
|
|
||||||
|
|
||||||
1. Open the Developer Tools Console
|
|
||||||
2. Enter `lastinfo.u.Temperature` to view the Temperature array
|
|
||||||
|
|
||||||
<img src="images/json-temp.png" width="300px"/>
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 296 KiB |
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
Binary file not shown.
Before Width: | Height: | Size: 321 KiB |
@ -1,16 +0,0 @@
|
|||||||
; QuinLED-Dig-Quad Preassembled Unofficial
|
|
||||||
|
|
||||||
[env:QL-DigQuad-Pre-v0.1]
|
|
||||||
extends = env:esp32dev
|
|
||||||
build_flags = ${common.build_flags_esp32}
|
|
||||||
-D ESP32_MULTISTRIP
|
|
||||||
-D NUM_STRIPS=4
|
|
||||||
-D PIXEL_COUNTS="600, 300, 300, 300"
|
|
||||||
-D DATA_PINS="16,1,3,26"
|
|
||||||
-D RLYPIN=19
|
|
||||||
-D BTNPIN=17
|
|
||||||
-D USERMOD_DALLASTEMPERATURE
|
|
||||||
-D USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL=10000
|
|
||||||
lib_deps = ${env.lib_deps}
|
|
||||||
milesburton/DallasTemperature@^3.9.0
|
|
||||||
OneWire@~2.3.5
|
|
@ -1,35 +0,0 @@
|
|||||||
# SSD1306 128x32 OLED via I2C with u8g2
|
|
||||||
This usermod allows to connect 128x32 Oled display to WLED controlled and show
|
|
||||||
the next information:
|
|
||||||
- Current SSID
|
|
||||||
- IP address if obtained
|
|
||||||
* in AP mode and turned off lightning AP password is shown
|
|
||||||
- Current effect
|
|
||||||
- Current palette
|
|
||||||
- On/Off icon (sun/moon)
|
|
||||||
|
|
||||||
## Hardware
|
|
||||||
![Hardware connection](assets/hw_connection.png)
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
Functionality checked with:
|
|
||||||
- commit 095429a7df4f9e2b34dd464f7bbfd068df6558eb
|
|
||||||
- Wemos d1 mini
|
|
||||||
- PlatformIO
|
|
||||||
- Generic SSD1306 128x32 I2C OLED display from aliexpress
|
|
||||||
|
|
||||||
### Platformio
|
|
||||||
Add `U8g2@~2.27.2` dependency to `lib_deps_external` under `[common]` section in `platformio.ini`:
|
|
||||||
```ini
|
|
||||||
# platformio.ini
|
|
||||||
...
|
|
||||||
[common]
|
|
||||||
...
|
|
||||||
lib_deps_external =
|
|
||||||
...
|
|
||||||
U8g2@~2.27.2
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
### Arduino IDE
|
|
||||||
Install library `U8g2 by oliver` in `Tools | Include Library | Manage libraries` menu.
|
|
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
@ -1,175 +0,0 @@
|
|||||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
|
||||||
|
|
||||||
//The SCL and SDA pins are defined here.
|
|
||||||
//Lolin32 boards use SCL=5 SDA=4
|
|
||||||
#define U8X8_PIN_SCL 5
|
|
||||||
#define U8X8_PIN_SDA 4
|
|
||||||
|
|
||||||
|
|
||||||
// If display does not work or looks corrupted check the
|
|
||||||
// constructor reference:
|
|
||||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
|
||||||
// or check the gallery:
|
|
||||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
|
||||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL,
|
|
||||||
U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
|
||||||
|
|
||||||
// gets called once at boot. Do all initialization that doesn't depend on
|
|
||||||
// network here
|
|
||||||
void userSetup() {
|
|
||||||
u8x8.begin();
|
|
||||||
u8x8.setPowerSave(0);
|
|
||||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
|
||||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
|
||||||
u8x8.drawString(0, 0, "Loading...");
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
|
||||||
// interfaces here
|
|
||||||
void userConnected() {}
|
|
||||||
|
|
||||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
|
||||||
bool needRedraw = true;
|
|
||||||
|
|
||||||
// Next variables hold the previous known values to determine if redraw is
|
|
||||||
// required.
|
|
||||||
String knownSsid = "";
|
|
||||||
IPAddress knownIp;
|
|
||||||
uint8_t knownBrightness = 0;
|
|
||||||
uint8_t knownMode = 0;
|
|
||||||
uint8_t knownPalette = 0;
|
|
||||||
|
|
||||||
long lastUpdate = 0;
|
|
||||||
long lastRedraw = 0;
|
|
||||||
bool displayTurnedOff = false;
|
|
||||||
// How often we are redrawing screen
|
|
||||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
|
||||||
|
|
||||||
void userLoop() {
|
|
||||||
|
|
||||||
// Check if we time interval for redrawing passes.
|
|
||||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastUpdate = millis();
|
|
||||||
|
|
||||||
// Turn off display after 3 minutes with no change.
|
|
||||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
|
||||||
u8x8.setPowerSave(1);
|
|
||||||
displayTurnedOff = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if values which are shown on display changed from the last time.
|
|
||||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
|
||||||
needRedraw = true;
|
|
||||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
|
||||||
needRedraw = true;
|
|
||||||
} else if (knownBrightness != bri) {
|
|
||||||
needRedraw = true;
|
|
||||||
} else if (knownMode != strip.getMode()) {
|
|
||||||
needRedraw = true;
|
|
||||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
|
||||||
needRedraw = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needRedraw) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
needRedraw = false;
|
|
||||||
|
|
||||||
if (displayTurnedOff)
|
|
||||||
{
|
|
||||||
u8x8.setPowerSave(0);
|
|
||||||
displayTurnedOff = false;
|
|
||||||
}
|
|
||||||
lastRedraw = millis();
|
|
||||||
|
|
||||||
// Update last known values.
|
|
||||||
#if defined(ESP8266)
|
|
||||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
|
||||||
#else
|
|
||||||
knownSsid = WiFi.SSID();
|
|
||||||
#endif
|
|
||||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
|
||||||
knownBrightness = bri;
|
|
||||||
knownMode = strip.getMode();
|
|
||||||
knownPalette = strip.getSegment(0).palette;
|
|
||||||
|
|
||||||
u8x8.clear();
|
|
||||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
|
||||||
|
|
||||||
// First row with Wifi name
|
|
||||||
u8x8.setCursor(1, 0);
|
|
||||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
|
||||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
|
||||||
if (knownSsid.length() > u8x8.getCols())
|
|
||||||
u8x8.print("~");
|
|
||||||
|
|
||||||
// Second row with IP or Psssword
|
|
||||||
u8x8.setCursor(1, 1);
|
|
||||||
// Print password in AP mode and if led is OFF.
|
|
||||||
if (apActive && bri == 0)
|
|
||||||
u8x8.print(apPass);
|
|
||||||
else
|
|
||||||
u8x8.print(knownIp);
|
|
||||||
|
|
||||||
// Third row with mode name
|
|
||||||
u8x8.setCursor(2, 2);
|
|
||||||
uint8_t qComma = 0;
|
|
||||||
bool insideQuotes = false;
|
|
||||||
uint8_t printedChars = 0;
|
|
||||||
char singleJsonSymbol;
|
|
||||||
// Find the mode name in JSON
|
|
||||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
|
||||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
|
||||||
switch (singleJsonSymbol) {
|
|
||||||
case '"':
|
|
||||||
insideQuotes = !insideQuotes;
|
|
||||||
break;
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
qComma++;
|
|
||||||
default:
|
|
||||||
if (!insideQuotes || (qComma != knownMode))
|
|
||||||
break;
|
|
||||||
u8x8.print(singleJsonSymbol);
|
|
||||||
printedChars++;
|
|
||||||
}
|
|
||||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Fourth row with palette name
|
|
||||||
u8x8.setCursor(2, 3);
|
|
||||||
qComma = 0;
|
|
||||||
insideQuotes = false;
|
|
||||||
printedChars = 0;
|
|
||||||
// Looking for palette name in JSON.
|
|
||||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
|
||||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
|
||||||
switch (singleJsonSymbol) {
|
|
||||||
case '"':
|
|
||||||
insideQuotes = !insideQuotes;
|
|
||||||
break;
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
qComma++;
|
|
||||||
default:
|
|
||||||
if (!insideQuotes || (qComma != knownPalette))
|
|
||||||
break;
|
|
||||||
u8x8.print(singleJsonSymbol);
|
|
||||||
printedChars++;
|
|
||||||
}
|
|
||||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
|
||||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
|
||||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
|
||||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
|
||||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
|
||||||
}
|
|
@ -65,6 +65,7 @@ class AutoSaveUsermod : public Usermod {
|
|||||||
month(localTime), day(localTime),
|
month(localTime), day(localTime),
|
||||||
hour(localTime), minute(localTime), second(localTime));
|
hour(localTime), minute(localTime), second(localTime));
|
||||||
savePreset(autoSavePreset, true, presetNameBuffer);
|
savePreset(autoSavePreset, true, presetNameBuffer);
|
||||||
|
cacheInvalidate++; // force reload of presets
|
||||||
}
|
}
|
||||||
|
|
||||||
void inline displayOverlay() {
|
void inline displayOverlay() {
|
||||||
|
@ -114,6 +114,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
||||||
#ifndef FLD_SPI_DEFAULT
|
#ifndef FLD_SPI_DEFAULT
|
||||||
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
|
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
|
||||||
|
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
|
||||||
DisplayType type = SSD1306; // display type
|
DisplayType type = SSD1306; // display type
|
||||||
#else
|
#else
|
||||||
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
|
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
|
||||||
@ -155,6 +156,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
static const char _flip[];
|
static const char _flip[];
|
||||||
static const char _sleepMode[];
|
static const char _sleepMode[];
|
||||||
static const char _clockMode[];
|
static const char _clockMode[];
|
||||||
|
static const char _busClkFrequency[];
|
||||||
|
|
||||||
// If display does not work or looks corrupted check the
|
// If display does not work or looks corrupted check the
|
||||||
// constructor reference:
|
// constructor reference:
|
||||||
@ -248,6 +250,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
|
|
||||||
initDone = true;
|
initDone = true;
|
||||||
DEBUG_PRINTLN(F("Starting display."));
|
DEBUG_PRINTLN(F("Starting display."));
|
||||||
|
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
u8x8->begin();
|
u8x8->begin();
|
||||||
setFlipMode(flip);
|
setFlipMode(flip);
|
||||||
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||||
@ -683,6 +686,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
|
top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
|
||||||
top[FPSTR(_sleepMode)] = (bool) sleepMode;
|
top[FPSTR(_sleepMode)] = (bool) sleepMode;
|
||||||
top[FPSTR(_clockMode)] = (bool) clockMode;
|
top[FPSTR(_clockMode)] = (bool) clockMode;
|
||||||
|
top[FPSTR(_busClkFrequency)] = ioFrequency/1000;
|
||||||
DEBUG_PRINTLN(F("4 Line Display config saved."));
|
DEBUG_PRINTLN(F("4 Line Display config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,6 +718,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
|
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
|
||||||
sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
|
sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
|
||||||
clockMode = top[FPSTR(_clockMode)] | clockMode;
|
clockMode = top[FPSTR(_clockMode)] | clockMode;
|
||||||
|
ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
@ -739,12 +744,13 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
setup();
|
setup();
|
||||||
needsRedraw |= true;
|
needsRedraw |= true;
|
||||||
}
|
}
|
||||||
|
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
setContrast(contrast);
|
setContrast(contrast);
|
||||||
setFlipMode(flip);
|
setFlipMode(flip);
|
||||||
if (needsRedraw && !wakeDisplay()) redraw(true);
|
if (needsRedraw && !wakeDisplay()) redraw(true);
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !(top["pin"][2]).isNull();
|
return !(top[_busClkFrequency]).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -757,10 +763,11 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
|
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
|
||||||
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
|
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
|
||||||
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRateSec";
|
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRateSec";
|
||||||
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
|
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
|
||||||
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
|
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
|
||||||
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
||||||
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
||||||
|
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
||||||
|
262
wled00/FX.cpp
262
wled00/FX.cpp
@ -388,41 +388,12 @@ uint16_t WS2812FX::mode_rainbow_cycle(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* theater chase function
|
|
||||||
*/
|
|
||||||
uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2, bool do_palette) {
|
|
||||||
byte gap = 2 + ((255 - SEGMENT.intensity) >> 5);
|
|
||||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2;
|
|
||||||
uint32_t it = now / cycleTime;
|
|
||||||
if (it != SEGENV.step) //new color
|
|
||||||
{
|
|
||||||
SEGENV.aux0 = (SEGENV.aux0 +1) % gap;
|
|
||||||
SEGENV.step = it;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
|
||||||
if((i % gap) == SEGENV.aux0) {
|
|
||||||
if (do_palette)
|
|
||||||
{
|
|
||||||
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
|
||||||
} else {
|
|
||||||
setPixelColor(i, color1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setPixelColor(i, color2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FRAMETIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Theatre-style crawling lights.
|
* Theatre-style crawling lights.
|
||||||
* Inspired by the Adafruit examples.
|
* Inspired by the Adafruit examples.
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_theater_chase(void) {
|
uint16_t WS2812FX::mode_theater_chase(void) {
|
||||||
return theater_chase(SEGCOLOR(0), SEGCOLOR(1), true);
|
return running(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -431,7 +402,7 @@ uint16_t WS2812FX::mode_theater_chase(void) {
|
|||||||
* Inspired by the Adafruit examples.
|
* Inspired by the Adafruit examples.
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
|
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
|
||||||
return theater_chase(color_wheel(SEGENV.step), SEGCOLOR(1), false);
|
return running(color_wheel(SEGENV.step), SEGCOLOR(1), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -976,29 +947,27 @@ uint16_t WS2812FX::mode_chase_flash_random(void) {
|
|||||||
/*
|
/*
|
||||||
* Alternating pixels running function.
|
* Alternating pixels running function.
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) {
|
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2, bool theatre) {
|
||||||
uint8_t pxw = 1 + (SEGMENT.intensity >> 5);
|
uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
|
||||||
uint32_t cycleTime = 35 + (255 - SEGMENT.speed);
|
uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
|
||||||
uint32_t it = now / cycleTime;
|
uint32_t it = now / cycleTime;
|
||||||
if (SEGMENT.speed == 0) it = 0;
|
bool usePalette = color1 == SEGCOLOR(0);
|
||||||
|
|
||||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
if((i + SEGENV.aux0) % (pxw*2) < pxw) {
|
uint32_t col = color2;
|
||||||
if (color1 == SEGCOLOR(0))
|
if (usePalette) color1 = color_from_palette(i, true, PALETTE_SOLID_WRAP, 0);
|
||||||
{
|
if (theatre) {
|
||||||
setPixelColor(SEGLEN -i -1, color_from_palette(SEGLEN -i -1, true, PALETTE_SOLID_WRAP, 0));
|
if ((i % width) == SEGENV.aux0) col = color1;
|
||||||
} else
|
|
||||||
{
|
|
||||||
setPixelColor(SEGLEN -i -1, color1);
|
|
||||||
}
|
|
||||||
} else {
|
} 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 )
|
if (it != SEGENV.step )
|
||||||
{
|
{
|
||||||
SEGENV.aux0 = (SEGENV.aux0 +1) % (pxw*2);
|
SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1));
|
||||||
SEGENV.step = it;
|
SEGENV.step = it;
|
||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
@ -1247,44 +1216,19 @@ uint16_t WS2812FX::mode_loading(void) {
|
|||||||
|
|
||||||
|
|
||||||
//American Police Light with all LEDs Red and Blue
|
//American Police Light with all LEDs Red and Blue
|
||||||
uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all)
|
uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, uint16_t width)
|
||||||
{
|
{
|
||||||
uint16_t counter = now * ((SEGMENT.speed >> 2) +1);
|
uint16_t delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster
|
||||||
uint16_t idexR = (counter * SEGLEN) >> 16;
|
uint32_t it = now / map(SEGMENT.speed, 0, 255, delay<<4, delay);
|
||||||
if (idexR >= SEGLEN) idexR = 0;
|
uint16_t offset = it % SEGLEN;
|
||||||
|
|
||||||
uint16_t topindex = SEGLEN >> 1;
|
|
||||||
uint16_t idexB = (idexR > topindex) ? idexR - topindex : idexR + topindex;
|
|
||||||
if (SEGENV.call == 0) SEGENV.aux0 = idexR;
|
|
||||||
if (idexB >= SEGLEN) idexB = 0; //otherwise overflow on odd number of LEDs
|
|
||||||
|
|
||||||
if (all) { //different algo, ensuring immediate fill
|
|
||||||
if (idexB > idexR) {
|
|
||||||
fill(color2);
|
|
||||||
for (uint16_t i = idexR; i < idexB; i++) setPixelColor(i, color1);
|
|
||||||
} else {
|
|
||||||
fill(color1);
|
|
||||||
for (uint16_t i = idexB; i < idexR; i++) setPixelColor(i, color2);
|
|
||||||
}
|
|
||||||
} else { //regular dot-only mode
|
|
||||||
uint8_t size = 1 + (SEGMENT.intensity >> 3);
|
|
||||||
if (size > SEGLEN/2) size = 1+ SEGLEN/2;
|
|
||||||
for (uint8_t i=0; i <= size; i++) {
|
|
||||||
setPixelColor(idexR+i, color1);
|
|
||||||
setPixelColor(idexB+i, color2);
|
|
||||||
}
|
|
||||||
if (SEGENV.aux0 != idexR) {
|
|
||||||
uint8_t gap = (SEGENV.aux0 < idexR)? idexR - SEGENV.aux0:SEGLEN - SEGENV.aux0 + idexR;
|
|
||||||
for (uint8_t i = 0; i <= gap ; i++) {
|
|
||||||
if ((idexR - i) < 0) idexR = SEGLEN-1 + i;
|
|
||||||
if ((idexB - i) < 0) idexB = SEGLEN-1 + i;
|
|
||||||
setPixelColor(idexR-i, color1);
|
|
||||||
setPixelColor(idexB-i, color2);
|
|
||||||
}
|
|
||||||
SEGENV.aux0 = idexR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!width) width = 1;
|
||||||
|
for (uint16_t i = 0; i < width; i++) {
|
||||||
|
uint16_t indexR = (offset + i) % SEGLEN;
|
||||||
|
uint16_t indexB = (offset + i + (SEGLEN>>1)) % SEGLEN;
|
||||||
|
setPixelColor(indexR, color1);
|
||||||
|
setPixelColor(indexB, color2);
|
||||||
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1292,7 +1236,7 @@ uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all)
|
|||||||
//American Police Light with all LEDs Red and Blue
|
//American Police Light with all LEDs Red and Blue
|
||||||
uint16_t WS2812FX::mode_police_all()
|
uint16_t WS2812FX::mode_police_all()
|
||||||
{
|
{
|
||||||
return police_base(RED, BLUE, true);
|
return police_base(RED, BLUE, (SEGLEN>>1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1300,15 +1244,15 @@ uint16_t WS2812FX::mode_police_all()
|
|||||||
uint16_t WS2812FX::mode_police()
|
uint16_t WS2812FX::mode_police()
|
||||||
{
|
{
|
||||||
fill(SEGCOLOR(1));
|
fill(SEGCOLOR(1));
|
||||||
|
return police_base(RED, BLUE, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
|
||||||
return police_base(RED, BLUE, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Police All with custom colors
|
//Police All with custom colors
|
||||||
uint16_t WS2812FX::mode_two_areas()
|
uint16_t WS2812FX::mode_two_areas()
|
||||||
{
|
{
|
||||||
return police_base(SEGCOLOR(0), SEGCOLOR(1), true);
|
fill(SEGCOLOR(2));
|
||||||
|
return police_base(SEGCOLOR(0), SEGCOLOR(1), ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1318,7 +1262,7 @@ uint16_t WS2812FX::mode_two_dots()
|
|||||||
fill(SEGCOLOR(2));
|
fill(SEGCOLOR(2));
|
||||||
uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
|
uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
|
||||||
|
|
||||||
return police_base(SEGCOLOR(0), color2, false);
|
return police_base(SEGCOLOR(0), color2, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1326,21 +1270,20 @@ uint16_t WS2812FX::mode_two_dots()
|
|||||||
* Tricolor chase function
|
* Tricolor chase function
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) {
|
uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) {
|
||||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2;
|
uint32_t cycleTime = 50 + ((255 - SEGMENT.speed)<<1);
|
||||||
uint32_t it = now / cycleTime;
|
uint32_t it = now / cycleTime; // iterator
|
||||||
uint8_t width = (1 + SEGMENT.intensity/32) * 3; //value of 1-8 for each colour
|
uint8_t width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour
|
||||||
uint8_t index = it % width;
|
uint8_t index = it % (width*3);
|
||||||
|
|
||||||
for(uint16_t i = 0; i < SEGLEN; i++, index++) {
|
for (uint16_t i = 0; i < SEGLEN; i++, index++) {
|
||||||
if(index > width-1) index = 0;
|
if (index > (width*3)-1) index = 0;
|
||||||
|
|
||||||
uint32_t color = color1;
|
uint32_t color = color1;
|
||||||
if(index > width*2/3-1) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1);
|
if (index > (width<<1)-1) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1);
|
||||||
else if(index > width/3-1) color = color2;
|
else if (index > width-1) color = color2;
|
||||||
|
|
||||||
setPixelColor(SEGLEN - i -1, color);
|
setPixelColor(SEGLEN - i -1, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1548,7 +1491,7 @@ uint16_t WS2812FX::mode_random_chase(void)
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//7 bytes
|
||||||
typedef struct Oscillator {
|
typedef struct Oscillator {
|
||||||
int16_t pos;
|
int16_t pos;
|
||||||
int8_t size;
|
int8_t size;
|
||||||
@ -1780,7 +1723,7 @@ uint16_t WS2812FX::mode_fire_2012()
|
|||||||
// Step 1. Cool down every cell a little
|
// Step 1. Cool down every cell a little
|
||||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
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
|
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||||
@ -1994,7 +1937,7 @@ uint16_t WS2812FX::mode_colortwinkle()
|
|||||||
|
|
||||||
if (fadeUp) {
|
if (fadeUp) {
|
||||||
CRGB incrementalColor = fastled_col;
|
CRGB incrementalColor = fastled_col;
|
||||||
incrementalColor.nscale8_video( fadeUpAmount);
|
incrementalColor.nscale8_video(fadeUpAmount);
|
||||||
fastled_col += incrementalColor;
|
fastled_col += incrementalColor;
|
||||||
|
|
||||||
if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
|
if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
|
||||||
@ -2002,24 +1945,21 @@ uint16_t WS2812FX::mode_colortwinkle()
|
|||||||
}
|
}
|
||||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
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;
|
fastled_col += fastled_col;
|
||||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fastled_col.nscale8( 255 - fadeDownAmount);
|
fastled_col.nscale8(255 - fadeDownAmount);
|
||||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
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) {
|
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);
|
int i = random16(SEGLEN);
|
||||||
if(getPixelColor(i) == 0) {
|
if (getPixelColor(i) == 0) {
|
||||||
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
|
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
|
||||||
uint16_t index = i >> 3;
|
uint16_t index = i >> 3;
|
||||||
uint8_t bitNum = i & 0x07;
|
uint8_t bitNum = i & 0x07;
|
||||||
@ -2170,10 +2110,14 @@ typedef struct Ripple {
|
|||||||
uint16_t pos;
|
uint16_t pos;
|
||||||
} ripple;
|
} ripple;
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#define MAX_RIPPLES 56
|
||||||
|
#else
|
||||||
|
#define MAX_RIPPLES 100
|
||||||
|
#endif
|
||||||
uint16_t WS2812FX::ripple_base(bool rainbow)
|
uint16_t WS2812FX::ripple_base(bool rainbow)
|
||||||
{
|
{
|
||||||
uint16_t maxRipples = 1 + (SEGLEN >> 2);
|
uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266
|
||||||
if (maxRipples > 100) maxRipples = 100;
|
|
||||||
uint16_t dataSize = sizeof(ripple) * maxRipples;
|
uint16_t dataSize = sizeof(ripple) * maxRipples;
|
||||||
|
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
@ -2241,6 +2185,7 @@ uint16_t WS2812FX::ripple_base(bool rainbow)
|
|||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
#undef MAX_RIPPLES
|
||||||
|
|
||||||
uint16_t WS2812FX::mode_ripple(void) {
|
uint16_t WS2812FX::mode_ripple(void) {
|
||||||
return ripple_base(false);
|
return ripple_base(false);
|
||||||
@ -2541,7 +2486,6 @@ uint16_t WS2812FX::mode_spots_fade()
|
|||||||
|
|
||||||
|
|
||||||
//each needs 12 bytes
|
//each needs 12 bytes
|
||||||
//Spark type is used for popcorn and 1D fireworks
|
|
||||||
typedef struct Ball {
|
typedef struct Ball {
|
||||||
unsigned long lastBounceTime;
|
unsigned long lastBounceTime;
|
||||||
float impactVelocity;
|
float impactVelocity;
|
||||||
@ -2651,7 +2595,7 @@ uint16_t WS2812FX::mode_sinelon_dual(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t WS2812FX::mode_sinelon_rainbow(void) {
|
uint16_t WS2812FX::mode_sinelon_rainbow(void) {
|
||||||
return sinelon_base(true, true);
|
return sinelon_base(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2670,7 +2614,7 @@ uint16_t WS2812FX::mode_glitter()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//each needs 12 bytes
|
//each needs 11 bytes
|
||||||
//Spark type is used for popcorn, 1D fireworks, and drip
|
//Spark type is used for popcorn, 1D fireworks, and drip
|
||||||
typedef struct Spark {
|
typedef struct Spark {
|
||||||
float pos;
|
float pos;
|
||||||
@ -2685,7 +2629,7 @@ typedef struct Spark {
|
|||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_popcorn(void) {
|
uint16_t WS2812FX::mode_popcorn(void) {
|
||||||
//allocate segment data
|
//allocate segment data
|
||||||
uint16_t maxNumPopcorn = 24;
|
uint16_t maxNumPopcorn = 22; // max 22 on 16 segment ESP8266
|
||||||
uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
|
uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
@ -2744,7 +2688,7 @@ uint16_t WS2812FX::candle(bool multi)
|
|||||||
if (multi)
|
if (multi)
|
||||||
{
|
{
|
||||||
//allocate segment data
|
//allocate segment data
|
||||||
uint16_t dataSize = (SEGLEN -1) *3;
|
uint16_t dataSize = (SEGLEN -1) *3; // max length of segment on 16 segment ESP8266 is 75 pixels
|
||||||
if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2831,9 +2775,14 @@ uint16_t WS2812FX::mode_candle_multi()
|
|||||||
/ based on the video: https://www.reddit.com/r/arduino/comments/c3sd46/i_made_this_fireworks_effect_for_my_led_strips/
|
/ based on the video: https://www.reddit.com/r/arduino/comments/c3sd46/i_made_this_fireworks_effect_for_my_led_strips/
|
||||||
/ Speed sets frequency of new starbursts, intensity is the intensity of the burst
|
/ Speed sets frequency of new starbursts, intensity is the intensity of the burst
|
||||||
*/
|
*/
|
||||||
#define STARBURST_MAX_FRAG 12
|
#ifdef ESP8266
|
||||||
|
#define STARBURST_MAX_FRAG 4
|
||||||
//each needs 64 byte
|
#define STARBURST_MAX_STARS 6
|
||||||
|
#else
|
||||||
|
#define STARBURST_MAX_FRAG 10
|
||||||
|
#define STARBURST_MAX_STARS 11
|
||||||
|
#endif
|
||||||
|
//each needs 18+STARBURST_MAX_FRAG*4 bytes
|
||||||
typedef struct particle {
|
typedef struct particle {
|
||||||
CRGB color;
|
CRGB color;
|
||||||
uint32_t birth =0;
|
uint32_t birth =0;
|
||||||
@ -2844,8 +2793,7 @@ typedef struct particle {
|
|||||||
} star;
|
} star;
|
||||||
|
|
||||||
uint16_t WS2812FX::mode_starburst(void) {
|
uint16_t WS2812FX::mode_starburst(void) {
|
||||||
uint8_t numStars = 1 + (SEGLEN >> 3);
|
uint8_t numStars = min(1 + (SEGLEN >> 3), STARBURST_MAX_STARS); // 11 * 58 * 32 = 19k (ESP32), 6 * 34 * 16 = 3.2k (ESP8266)
|
||||||
if (numStars > 15) numStars = 15;
|
|
||||||
uint16_t dataSize = sizeof(star) * numStars;
|
uint16_t dataSize = sizeof(star) * numStars;
|
||||||
|
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
@ -2946,18 +2894,22 @@ uint16_t WS2812FX::mode_starburst(void) {
|
|||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
#undef STARBURST_MAX_FRAG
|
||||||
|
#undef STARBURST_MAX_STARS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exploding fireworks effect
|
* Exploding fireworks effect
|
||||||
* adapted from: http://www.anirama.com/1000leds/1d-fireworks/
|
* adapted from: http://www.anirama.com/1000leds/1d-fireworks/
|
||||||
*/
|
*/
|
||||||
|
#ifdef ESP8266
|
||||||
|
#define MAX_SPARKS 20 // number of fragments (11 bytes per fragment)
|
||||||
|
#else
|
||||||
|
#define MAX_SPARKS 58 // number of fragments
|
||||||
|
#endif
|
||||||
uint16_t WS2812FX::mode_exploding_fireworks(void)
|
uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||||
{
|
{
|
||||||
//allocate segment data
|
//allocate segment data
|
||||||
uint16_t numSparks = 2 + (SEGLEN >> 1);
|
uint16_t numSparks = min(2 + (SEGLEN >> 1), MAX_SPARKS); // max 58 for 32 segment ESP32, 20 for 16 segment ESP8266
|
||||||
if (numSparks > 80) numSparks = 80;
|
|
||||||
uint16_t dataSize = sizeof(spark) * numSparks;
|
uint16_t dataSize = sizeof(spark) * numSparks;
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
@ -3052,7 +3004,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
|||||||
SEGENV.aux0--;
|
SEGENV.aux0--;
|
||||||
if (SEGENV.aux0 < 4) {
|
if (SEGENV.aux0 < 4) {
|
||||||
SEGENV.aux0 = 0; //back to flare
|
SEGENV.aux0 = 0; //back to flare
|
||||||
SEGENV.step = (SEGMENT.intensity > random8()); //decide firing side
|
SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3060,6 +3012,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
#undef MAX_SPARKS
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3069,7 +3022,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
|||||||
uint16_t WS2812FX::mode_drip(void)
|
uint16_t WS2812FX::mode_drip(void)
|
||||||
{
|
{
|
||||||
//allocate segment data
|
//allocate segment data
|
||||||
uint16_t numDrops = 4;
|
uint8_t numDrops = 4;
|
||||||
uint16_t dataSize = sizeof(spark) * numDrops;
|
uint16_t dataSize = sizeof(spark) * numDrops;
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
@ -3077,7 +3030,7 @@ uint16_t WS2812FX::mode_drip(void)
|
|||||||
|
|
||||||
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
|
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
|
||||||
|
|
||||||
numDrops = 1 + (SEGMENT.intensity >> 6);
|
numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
|
||||||
|
|
||||||
float gravity = -0.0005 - (SEGMENT.speed/50000.0);
|
float gravity = -0.0005 - (SEGMENT.speed/50000.0);
|
||||||
gravity *= SEGLEN;
|
gravity *= SEGLEN;
|
||||||
@ -3107,13 +3060,13 @@ uint16_t WS2812FX::mode_drip(void)
|
|||||||
if (drops[j].pos > 0) { // fall until end of segment
|
if (drops[j].pos > 0) { // fall until end of segment
|
||||||
drops[j].pos += drops[j].vel;
|
drops[j].pos += drops[j].vel;
|
||||||
if (drops[j].pos < 0) drops[j].pos = 0;
|
if (drops[j].pos < 0) drops[j].pos = 0;
|
||||||
drops[j].vel += gravity;
|
drops[j].vel += gravity; // gravity is negative
|
||||||
|
|
||||||
for (uint16_t i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
|
for (uint16_t i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
|
||||||
uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
|
uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
|
||||||
setPixelColor(pos,color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling
|
setPixelColor(pos,color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
|
if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
|
||||||
setPixelColor(0,color_blend(SEGCOLOR(0),BLACK,drops[j].col));
|
setPixelColor(0,color_blend(SEGCOLOR(0),BLACK,drops[j].col));
|
||||||
}
|
}
|
||||||
@ -3142,6 +3095,7 @@ uint16_t WS2812FX::mode_drip(void)
|
|||||||
* Tetris or Stacking (falling bricks) Effect
|
* Tetris or Stacking (falling bricks) Effect
|
||||||
* by Blaz Kristan (https://github.com/blazoncek, https://blaz.at/home)
|
* by Blaz Kristan (https://github.com/blazoncek, https://blaz.at/home)
|
||||||
*/
|
*/
|
||||||
|
//12 bytes
|
||||||
typedef struct Tetris {
|
typedef struct Tetris {
|
||||||
float pos;
|
float pos;
|
||||||
float speed;
|
float speed;
|
||||||
@ -3163,8 +3117,8 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (SEGENV.step == 0) { //init
|
if (SEGENV.step == 0) { //init
|
||||||
drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>3)+1 : random8(6,40)); // set speed
|
drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>2)+1 : random8(6,64)); // set speed
|
||||||
drop->pos = SEGLEN-1; // start at end of segment
|
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
|
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.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
|
SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
|
||||||
@ -3196,13 +3150,17 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
|||||||
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
|
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_plasma(void) {
|
uint16_t WS2812FX::mode_plasma(void) {
|
||||||
uint8_t thisPhase = beatsin8(6,-64,64); // Setting phase change for a couple of waves.
|
// initialize phases on start
|
||||||
uint8_t thatPhase = beatsin8(7,-64,64);
|
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:
|
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.
|
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.
|
+ 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 thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1))));
|
||||||
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
|
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
|
||||||
setPixelColor(i, color.red, color.green, color.blue);
|
setPixelColor(i, color.red, color.green, color.blue);
|
||||||
}
|
}
|
||||||
@ -3531,7 +3489,7 @@ uint16_t WS2812FX::mode_noisepal(void) { // S
|
|||||||
uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
|
uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
|
||||||
//#define scale 30
|
//#define scale 30
|
||||||
|
|
||||||
uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes
|
uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes)
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
CRGBPalette16* palettes = reinterpret_cast<CRGBPalette16*>(SEGENV.data);
|
CRGBPalette16* palettes = reinterpret_cast<CRGBPalette16*>(SEGENV.data);
|
||||||
@ -3644,7 +3602,7 @@ uint16_t WS2812FX::mode_chunchun(void)
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//13 bytes
|
||||||
typedef struct Spotlight {
|
typedef struct Spotlight {
|
||||||
float speed;
|
float speed;
|
||||||
uint8_t colorIdx;
|
uint8_t colorIdx;
|
||||||
@ -3661,6 +3619,11 @@ typedef struct Spotlight {
|
|||||||
#define SPOT_TYPE_3X_DOT 4
|
#define SPOT_TYPE_3X_DOT 4
|
||||||
#define SPOT_TYPE_4X_DOT 5
|
#define SPOT_TYPE_4X_DOT 5
|
||||||
#define SPOT_TYPES_COUNT 6
|
#define SPOT_TYPES_COUNT 6
|
||||||
|
#ifdef ESP8266
|
||||||
|
#define SPOT_MAX_COUNT 17 //Number of simultaneous waves
|
||||||
|
#else
|
||||||
|
#define SPOT_MAX_COUNT 49 //Number of simultaneous waves
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Spotlights moving back and forth that cast dancing shadows.
|
* Spotlights moving back and forth that cast dancing shadows.
|
||||||
@ -3671,7 +3634,7 @@ typedef struct Spotlight {
|
|||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_dancing_shadows(void)
|
uint16_t WS2812FX::mode_dancing_shadows(void)
|
||||||
{
|
{
|
||||||
uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, 50);
|
uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 16 segment ESP8266
|
||||||
bool initialize = SEGENV.aux0 != numSpotlights;
|
bool initialize = SEGENV.aux0 != numSpotlights;
|
||||||
SEGENV.aux0 = numSpotlights;
|
SEGENV.aux0 = numSpotlights;
|
||||||
|
|
||||||
@ -3810,7 +3773,7 @@ uint16_t WS2812FX::mode_washing_machine(void) {
|
|||||||
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
|
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_blends(void) {
|
uint16_t WS2812FX::mode_blends(void) {
|
||||||
uint16_t dataSize = sizeof(uint32_t) * SEGLEN;
|
uint16_t dataSize = sizeof(uint32_t) * SEGLEN; // max segment length of 56 pixels on 16 segment ESP8266
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||||
uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
|
uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
|
||||||
@ -3825,6 +3788,11 @@ uint16_t WS2812FX::mode_blends(void) {
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TV Simulator
|
||||||
|
Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch
|
||||||
|
*/
|
||||||
|
//43 bytes
|
||||||
typedef struct TvSim {
|
typedef struct TvSim {
|
||||||
uint32_t totalTime = 0;
|
uint32_t totalTime = 0;
|
||||||
uint32_t fadeTime = 0;
|
uint32_t fadeTime = 0;
|
||||||
@ -3845,11 +3813,6 @@ typedef struct TvSim {
|
|||||||
uint16_t pb = 0;
|
uint16_t pb = 0;
|
||||||
} tvSim;
|
} tvSim;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
TV Simulator
|
|
||||||
Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch
|
|
||||||
*/
|
|
||||||
uint16_t WS2812FX::mode_tv_simulator(void) {
|
uint16_t WS2812FX::mode_tv_simulator(void) {
|
||||||
uint16_t nr, ng, nb, r, g, b, i, hue;
|
uint16_t nr, ng, nb, r, g, b, i, hue;
|
||||||
uint8_t sat, bri, j;
|
uint8_t sat, bri, j;
|
||||||
@ -3957,10 +3920,15 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//CONFIG
|
//CONFIG
|
||||||
#define W_MAX_COUNT 20 //Number of simultaneous waves
|
#ifdef ESP8266
|
||||||
|
#define W_MAX_COUNT 9 //Number of simultaneous waves
|
||||||
|
#else
|
||||||
|
#define W_MAX_COUNT 20 //Number of simultaneous waves
|
||||||
|
#endif
|
||||||
#define W_MAX_SPEED 6 //Higher number, higher speed
|
#define W_MAX_SPEED 6 //Higher number, higher speed
|
||||||
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
|
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
|
||||||
|
|
||||||
|
//24 bytes
|
||||||
class AuroraWave {
|
class AuroraWave {
|
||||||
private:
|
private:
|
||||||
uint16_t ttl;
|
uint16_t ttl;
|
||||||
@ -4055,10 +4023,10 @@ uint16_t WS2812FX::mode_aurora(void) {
|
|||||||
|
|
||||||
if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
|
if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
|
||||||
//Intensity slider changed or first call
|
//Intensity slider changed or first call
|
||||||
SEGENV.aux1 = ((float)SEGMENT.intensity / 255) * W_MAX_COUNT;
|
SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT);
|
||||||
SEGENV.aux0 = SEGMENT.intensity;
|
SEGENV.aux0 = SEGMENT.intensity;
|
||||||
|
|
||||||
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) {
|
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 16 segment ESP8266
|
||||||
return mode_static(); //allocation failed
|
return mode_static(); //allocation failed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
71
wled00/FX.h
71
wled00/FX.h
@ -24,8 +24,6 @@
|
|||||||
Modified for WLED
|
Modified for WLED
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "wled.h"
|
|
||||||
|
|
||||||
#ifndef WS2812FX_h
|
#ifndef WS2812FX_h
|
||||||
#define WS2812FX_h
|
#define WS2812FX_h
|
||||||
|
|
||||||
@ -55,17 +53,17 @@
|
|||||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define MAX_NUM_SEGMENTS 12
|
#define MAX_NUM_SEGMENTS 16
|
||||||
/* How many color transitions can run at once */
|
/* How many color transitions can run at once */
|
||||||
#define MAX_NUM_TRANSITIONS 8
|
#define MAX_NUM_TRANSITIONS 8
|
||||||
/* How much data bytes all segments combined may allocate */
|
/* How much data bytes all segments combined may allocate */
|
||||||
#define MAX_SEGMENT_DATA 2048
|
#define MAX_SEGMENT_DATA 3584
|
||||||
#else
|
#else
|
||||||
#ifndef MAX_NUM_SEGMENTS
|
#ifndef MAX_NUM_SEGMENTS
|
||||||
#define MAX_NUM_SEGMENTS 16
|
#define MAX_NUM_SEGMENTS 32
|
||||||
#endif
|
#endif
|
||||||
#define MAX_NUM_TRANSITIONS 16
|
#define MAX_NUM_TRANSITIONS 24
|
||||||
#define MAX_SEGMENT_DATA 8192
|
#define MAX_SEGMENT_DATA 20480
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LED_SKIP_AMOUNT 1
|
#define LED_SKIP_AMOUNT 1
|
||||||
@ -257,6 +255,7 @@ class WS2812FX {
|
|||||||
uint8_t grouping, spacing;
|
uint8_t grouping, spacing;
|
||||||
uint8_t opacity;
|
uint8_t opacity;
|
||||||
uint32_t colors[NUM_COLORS];
|
uint32_t colors[NUM_COLORS];
|
||||||
|
char *name;
|
||||||
bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
|
bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
|
||||||
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
|
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
|
||||||
if (c == colors[slot]) return false;
|
if (c == colors[slot]) return false;
|
||||||
@ -296,19 +295,19 @@ class WS2812FX {
|
|||||||
{
|
{
|
||||||
return ((options >> n) & 0x01);
|
return ((options >> n) & 0x01);
|
||||||
}
|
}
|
||||||
bool isSelected()
|
inline bool isSelected()
|
||||||
{
|
{
|
||||||
return getOption(0);
|
return getOption(0);
|
||||||
}
|
}
|
||||||
bool isActive()
|
inline bool isActive()
|
||||||
{
|
{
|
||||||
return stop > start;
|
return stop > start;
|
||||||
}
|
}
|
||||||
uint16_t length()
|
inline uint16_t length()
|
||||||
{
|
{
|
||||||
return stop - start;
|
return stop - start;
|
||||||
}
|
}
|
||||||
uint16_t groupLength()
|
inline uint16_t groupLength()
|
||||||
{
|
{
|
||||||
return grouping + spacing;
|
return grouping + spacing;
|
||||||
}
|
}
|
||||||
@ -345,17 +344,23 @@ class WS2812FX {
|
|||||||
|
|
||||||
// segment runtime parameters
|
// segment runtime parameters
|
||||||
typedef struct Segment_runtime { // 28 bytes
|
typedef struct Segment_runtime { // 28 bytes
|
||||||
unsigned long next_time;
|
unsigned long next_time; // millis() of next update
|
||||||
uint32_t step;
|
uint32_t step; // custom "step" var
|
||||||
uint32_t call;
|
uint32_t call; // call counter
|
||||||
uint16_t aux0;
|
uint16_t aux0; // custom var
|
||||||
uint16_t aux1;
|
uint16_t aux1; // custom var
|
||||||
byte* data = nullptr;
|
byte* data = nullptr;
|
||||||
bool allocateData(uint16_t len){
|
bool allocateData(uint16_t len){
|
||||||
if (data && _dataLen == len) return true; //already allocated
|
if (data && _dataLen == len) return true; //already allocated
|
||||||
deallocateData();
|
deallocateData();
|
||||||
if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||||
data = new (std::nothrow) byte[len];
|
// if possible use SPI RAM on ESP32
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||||
|
if (psramFound())
|
||||||
|
data = (byte*) ps_malloc(len);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
data = (byte*) malloc(len);
|
||||||
if (!data) return false; //allocation failed
|
if (!data) return false; //allocation failed
|
||||||
WS2812FX::instance->_usedSegmentData += len;
|
WS2812FX::instance->_usedSegmentData += len;
|
||||||
_dataLen = len;
|
_dataLen = len;
|
||||||
@ -363,7 +368,7 @@ class WS2812FX {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void deallocateData(){
|
void deallocateData(){
|
||||||
delete[] data;
|
free(data);
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
WS2812FX::instance->_usedSegmentData -= _dataLen;
|
WS2812FX::instance->_usedSegmentData -= _dataLen;
|
||||||
_dataLen = 0;
|
_dataLen = 0;
|
||||||
@ -389,7 +394,7 @@ class WS2812FX {
|
|||||||
* the internal segment state should be reset.
|
* the internal segment state should be reset.
|
||||||
* Call resetIfRequired before calling the next effect function.
|
* Call resetIfRequired before calling the next effect function.
|
||||||
*/
|
*/
|
||||||
void reset() { _requiresReset = true; }
|
inline void reset() { _requiresReset = true; }
|
||||||
private:
|
private:
|
||||||
uint16_t _dataLen = 0;
|
uint16_t _dataLen = 0;
|
||||||
bool _requiresReset = false;
|
bool _requiresReset = false;
|
||||||
@ -605,7 +610,7 @@ class WS2812FX {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
finalizeInit(uint16_t countPixels),
|
finalizeInit(void),
|
||||||
service(void),
|
service(void),
|
||||||
blur(uint8_t),
|
blur(uint8_t),
|
||||||
fill(uint32_t),
|
fill(uint32_t),
|
||||||
@ -622,11 +627,12 @@ class WS2812FX {
|
|||||||
trigger(void),
|
trigger(void),
|
||||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
|
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
|
||||||
resetSegments(),
|
resetSegments(),
|
||||||
|
populateDefaultSegments(),
|
||||||
setPixelColor(uint16_t n, uint32_t c),
|
setPixelColor(uint16_t n, uint32_t c),
|
||||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||||
show(void),
|
show(void),
|
||||||
setColorOrder(uint8_t co),
|
setPixelSegment(uint8_t n),
|
||||||
setPixelSegment(uint8_t n);
|
deserializeMap(uint8_t n=0);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isRgbw = false,
|
isRgbw = false,
|
||||||
@ -644,8 +650,6 @@ class WS2812FX {
|
|||||||
paletteFade = 0,
|
paletteFade = 0,
|
||||||
paletteBlend = 0,
|
paletteBlend = 0,
|
||||||
milliampsPerLed = 55,
|
milliampsPerLed = 55,
|
||||||
// getStripType(uint8_t strip=0),
|
|
||||||
// setStripType(uint8_t type, uint8_t strip=0),
|
|
||||||
getBrightness(void),
|
getBrightness(void),
|
||||||
getMode(void),
|
getMode(void),
|
||||||
getSpeed(void),
|
getSpeed(void),
|
||||||
@ -654,24 +658,17 @@ class WS2812FX {
|
|||||||
getMaxSegments(void),
|
getMaxSegments(void),
|
||||||
//getFirstSelectedSegment(void),
|
//getFirstSelectedSegment(void),
|
||||||
getMainSegmentId(void),
|
getMainSegmentId(void),
|
||||||
getColorOrder(void),
|
|
||||||
gamma8(uint8_t),
|
gamma8(uint8_t),
|
||||||
gamma8_cal(uint8_t, float),
|
gamma8_cal(uint8_t, float),
|
||||||
sin_gap(uint16_t),
|
sin_gap(uint16_t),
|
||||||
get_random_wheel_index(uint8_t);
|
get_random_wheel_index(uint8_t);
|
||||||
|
|
||||||
int8_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);
|
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
|
||||||
|
|
||||||
uint16_t
|
uint16_t
|
||||||
ablMilliampsMax,
|
ablMilliampsMax,
|
||||||
currentMilliamps,
|
currentMilliamps,
|
||||||
// setStripLen(uint8_t strip, uint16_t len),
|
|
||||||
// getStripLen(uint8_t strip=0),
|
|
||||||
triwave16(uint16_t),
|
triwave16(uint16_t),
|
||||||
getFps();
|
getFps();
|
||||||
|
|
||||||
@ -849,7 +846,6 @@ class WS2812FX {
|
|||||||
color_wipe(bool, bool),
|
color_wipe(bool, bool),
|
||||||
dynamic(bool),
|
dynamic(bool),
|
||||||
scan(bool),
|
scan(bool),
|
||||||
theater_chase(uint32_t, uint32_t, bool),
|
|
||||||
running_base(bool,bool),
|
running_base(bool,bool),
|
||||||
larson_scanner(bool),
|
larson_scanner(bool),
|
||||||
sinelon_base(bool,bool),
|
sinelon_base(bool,bool),
|
||||||
@ -857,8 +853,8 @@ class WS2812FX {
|
|||||||
chase(uint32_t, uint32_t, uint32_t, bool),
|
chase(uint32_t, uint32_t, uint32_t, bool),
|
||||||
gradient_base(bool),
|
gradient_base(bool),
|
||||||
ripple_base(bool),
|
ripple_base(bool),
|
||||||
police_base(uint32_t, uint32_t, bool),
|
police_base(uint32_t, uint32_t, uint16_t),
|
||||||
running(uint32_t, uint32_t),
|
running(uint32_t, uint32_t, bool theatre=false),
|
||||||
tricolor_chase(uint32_t, uint32_t),
|
tricolor_chase(uint32_t, uint32_t),
|
||||||
twinklefox_base(bool),
|
twinklefox_base(bool),
|
||||||
spots_base(uint16_t),
|
spots_base(uint16_t),
|
||||||
@ -869,8 +865,7 @@ class WS2812FX {
|
|||||||
|
|
||||||
void
|
void
|
||||||
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
|
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
|
||||||
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot),
|
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot);
|
||||||
deserializeMap(void);
|
|
||||||
|
|
||||||
uint16_t* customMappingTable = nullptr;
|
uint16_t* customMappingTable = nullptr;
|
||||||
uint16_t customMappingSize = 0;
|
uint16_t customMappingSize = 0;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
Modified heavily for WLED
|
Modified heavily for WLED
|
||||||
*/
|
*/
|
||||||
|
#include "wled.h"
|
||||||
#include "FX.h"
|
#include "FX.h"
|
||||||
#include "palettes.h"
|
#include "palettes.h"
|
||||||
|
|
||||||
@ -40,7 +40,7 @@
|
|||||||
another example. Switches direction every 5 LEDs.
|
another example. Switches direction every 5 LEDs.
|
||||||
{"map":[
|
{"map":[
|
||||||
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
||||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]
|
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//factory defaults LED setup
|
//factory defaults LED setup
|
||||||
@ -49,7 +49,7 @@
|
|||||||
//#define DEFAULT_LED_TYPE TYPE_WS2812_RGB
|
//#define DEFAULT_LED_TYPE TYPE_WS2812_RGB
|
||||||
|
|
||||||
#ifndef PIXEL_COUNTS
|
#ifndef PIXEL_COUNTS
|
||||||
#define PIXEL_COUNTS DEFAULT_LED_COUNT
|
#define PIXEL_COUNTS 30
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DATA_PINS
|
#ifndef DATA_PINS
|
||||||
@ -65,25 +65,22 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//do not call this method from system context (network callback)
|
//do not call this method from system context (network callback)
|
||||||
void WS2812FX::finalizeInit(uint16_t countPixels)
|
void WS2812FX::finalizeInit(void)
|
||||||
{
|
{
|
||||||
RESET_RUNTIME;
|
RESET_RUNTIME;
|
||||||
_length = countPixels;
|
isRgbw = isOffRefreshRequred = false;
|
||||||
|
|
||||||
//if busses failed to load, add default (FS issue...)
|
//if busses failed to load, add default (fresh install, FS issue, ...)
|
||||||
if (busses.getNumBusses() == 0) {
|
if (busses.getNumBusses() == 0) {
|
||||||
const uint8_t defDataPins[] = {DATA_PINS};
|
const uint8_t defDataPins[] = {DATA_PINS};
|
||||||
const uint16_t defCounts[] = {PIXEL_COUNTS};
|
const uint16_t defCounts[] = {PIXEL_COUNTS};
|
||||||
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
|
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0])); // min 1
|
||||||
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
|
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); // min 1
|
||||||
uint16_t prevLen = 0;
|
uint16_t prevLen = 0;
|
||||||
for (uint8_t i = 0; i < defNumBusses; i++) {
|
for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES; i++) {
|
||||||
uint8_t defPin[] = {defDataPins[i]};
|
uint8_t defPin[] = {defDataPins[i]};
|
||||||
uint16_t start = prevLen;
|
uint16_t start = prevLen;
|
||||||
uint16_t count = _length;
|
uint16_t count = (i < defNumCounts) ? defCounts[i] : defCounts[i>0?i-1:0];
|
||||||
if (defNumBusses > 1 && defNumCounts) {
|
|
||||||
count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
|
||||||
}
|
|
||||||
prevLen += count;
|
prevLen += count;
|
||||||
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB);
|
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB);
|
||||||
busses.add(defCfg);
|
busses.add(defCfg);
|
||||||
@ -92,65 +89,33 @@ void WS2812FX::finalizeInit(uint16_t countPixels)
|
|||||||
|
|
||||||
deserializeMap();
|
deserializeMap();
|
||||||
|
|
||||||
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
|
_length = 0;
|
||||||
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
|
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||||
|
Bus *bus = busses.getBus(i);
|
||||||
|
if (bus == nullptr) continue;
|
||||||
|
if (_length+bus->getLength() > MAX_LEDS) break;
|
||||||
|
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||||
|
isRgbw |= bus->isRgbw();
|
||||||
|
//refresh is required to remain off if at least one of the strips requires the refresh.
|
||||||
|
isOffRefreshRequred |= BusManager::isOffRefreshRequred(bus->getType());
|
||||||
|
_length += bus->getLength();
|
||||||
|
}
|
||||||
|
ledCount = _length;
|
||||||
|
|
||||||
|
// We will create default segments im populateDefaultSegments()
|
||||||
|
|
||||||
setBrightness(_brightness);
|
setBrightness(_brightness);
|
||||||
|
|
||||||
//TODO make sure segments are only refreshed when bus config actually changed (new settings page)
|
#ifdef ESP8266
|
||||||
uint8_t s = 0;
|
|
||||||
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
|
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
|
||||||
Bus* b = busses.getBus(i);
|
Bus* b = busses.getBus(i);
|
||||||
|
|
||||||
if (autoSegments) { //make one segment per bus
|
|
||||||
segStarts[s] = b->getStart();
|
|
||||||
segStops[s] = segStarts[s] + b->getLength();
|
|
||||||
|
|
||||||
//check for overlap with previous segments
|
|
||||||
for (uint8_t j = 0; j < s; j++) {
|
|
||||||
if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) {
|
|
||||||
//segments overlap, merge
|
|
||||||
segStarts[j] = min(segStarts[s],segStarts[j]);
|
|
||||||
segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0;
|
|
||||||
s--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue;
|
if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue;
|
||||||
uint8_t pins[5];
|
uint8_t pins[5];
|
||||||
b->getPins(pins);
|
b->getPins(pins);
|
||||||
BusDigital* bd = static_cast<BusDigital*>(b);
|
BusDigital* bd = static_cast<BusDigital*>(b);
|
||||||
if (pins[0] == 3) bd->reinit();
|
if (pins[0] == 3) bd->reinit();
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (autoSegments) {
|
|
||||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {
|
|
||||||
_segments[i].start = segStarts[i];
|
|
||||||
_segments[i].stop = segStops [i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//expand the main seg to the entire length, but only if there are no other segments
|
|
||||||
uint8_t mainSeg = getMainSegmentId();
|
|
||||||
bool isMultipleSegs = false;
|
|
||||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
|
||||||
{
|
|
||||||
if (i != mainSeg && _segments[i].isActive()) isMultipleSegs = true;
|
|
||||||
}
|
|
||||||
if (!isMultipleSegs) {
|
|
||||||
_segments[mainSeg].start = 0; _segments[mainSeg].stop = _length;
|
|
||||||
} else {
|
|
||||||
//there are multiple segments, leave them, but prune length to total
|
|
||||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
|
||||||
{
|
|
||||||
if (_segments[i].start > _length) _segments[i].stop = 0;
|
|
||||||
if (_segments[i].stop > _length) _segments[i].stop = _length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::service() {
|
void WS2812FX::service() {
|
||||||
@ -218,14 +183,13 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
|||||||
int16_t realIndex = iGroup;
|
int16_t realIndex = iGroup;
|
||||||
if (IS_REVERSE) {
|
if (IS_REVERSE) {
|
||||||
if (IS_MIRROR) {
|
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 {
|
} else {
|
||||||
realIndex = SEGMENT.length() - iGroup - 1;
|
realIndex = (SEGMENT.length() - 1) - iGroup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
realIndex += SEGMENT.start;
|
realIndex += SEGMENT.start;
|
||||||
|
|
||||||
return realIndex;
|
return realIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +210,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (SEGLEN) {//from segment
|
if (SEGLEN) {//from segment
|
||||||
|
|
||||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||||
if (_bri_t < 255) {
|
if (_bri_t < 255) {
|
||||||
r = scale8(r, _bri_t);
|
r = scale8(r, _bri_t);
|
||||||
@ -256,12 +219,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
|||||||
}
|
}
|
||||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||||
|
|
||||||
bool reversed = IS_REVERSE;
|
/* Set all the pixels in the group */
|
||||||
uint16_t realIndex = realPixelIndex(i);
|
uint16_t realIndex = realPixelIndex(i);
|
||||||
uint16_t len = SEGMENT.length();
|
uint16_t len = SEGMENT.length();
|
||||||
|
|
||||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||||
int indexSet = realIndex + (reversed ? -j : j);
|
uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
|
||||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
||||||
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
||||||
uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1;
|
uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1;
|
||||||
@ -273,8 +236,8 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
|||||||
busses.setPixelColor(indexMir, col);
|
busses.setPixelColor(indexMir, col);
|
||||||
}
|
}
|
||||||
/* offset/phase */
|
/* offset/phase */
|
||||||
indexSet += SEGMENT.offset;
|
indexSet += SEGMENT.offset;
|
||||||
if (indexSet >= SEGMENT.stop) indexSet -= len;
|
if (indexSet >= SEGMENT.stop) indexSet -= len;
|
||||||
|
|
||||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||||
busses.setPixelColor(indexSet, col);
|
busses.setPixelColor(indexSet, col);
|
||||||
@ -282,7 +245,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
|||||||
}
|
}
|
||||||
} else { //live data, etc.
|
} else { //live data, etc.
|
||||||
if (i < customMappingSize) i = customMappingTable[i];
|
if (i < customMappingSize) i = customMappingTable[i];
|
||||||
|
|
||||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||||
busses.setPixelColor(i, col);
|
busses.setPixelColor(i, col);
|
||||||
}
|
}
|
||||||
@ -563,7 +525,9 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i < customMappingSize) i = customMappingTable[i];
|
if (i < customMappingSize) i = customMappingTable[i];
|
||||||
|
if (i >= _length) return 0;
|
||||||
|
|
||||||
|
// TODO: may need to add IS_REVERSE and IS_MIRROR logic
|
||||||
return busses.getPixelColor(i);
|
return busses.getPixelColor(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,14 +548,14 @@ uint32_t WS2812FX::getLastShow(void) {
|
|||||||
return _lastShow;
|
return _lastShow;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO these need to be on a per-strip basis
|
// there is no longer any need for these two
|
||||||
uint8_t WS2812FX::getColorOrder(void) {
|
//uint8_t WS2812FX::getColorOrder(void) {
|
||||||
return COL_ORDER_GRB;
|
// return COL_ORDER_GRB;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
void WS2812FX::setColorOrder(uint8_t co) {
|
//void WS2812FX::setColorOrder(uint8_t co) {
|
||||||
//bus->SetColorOrder(co);
|
// //bus->SetColorOrder(co);
|
||||||
}
|
//}
|
||||||
|
|
||||||
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
|
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
|
||||||
if (n >= MAX_NUM_SEGMENTS) return;
|
if (n >= MAX_NUM_SEGMENTS) return;
|
||||||
@ -603,7 +567,11 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
|
|||||||
if (seg.stop) setRange(seg.start, seg.stop -1, 0); //turn old segment range off
|
if (seg.stop) setRange(seg.start, seg.stop -1, 0); //turn old segment range off
|
||||||
if (i2 <= i1) //disable segment
|
if (i2 <= i1) //disable segment
|
||||||
{
|
{
|
||||||
seg.stop = 0;
|
seg.stop = 0;
|
||||||
|
if (seg.name) {
|
||||||
|
delete[] seg.name;
|
||||||
|
seg.name = nullptr;
|
||||||
|
}
|
||||||
if (n == mainSegment) //if main segment is deleted, set first active as main segment
|
if (n == mainSegment) //if main segment is deleted, set first active as main segment
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||||
@ -628,6 +596,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::resetSegments() {
|
void WS2812FX::resetSegments() {
|
||||||
|
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete _segments[i].name;
|
||||||
mainSegment = 0;
|
mainSegment = 0;
|
||||||
memset(_segments, 0, sizeof(_segments));
|
memset(_segments, 0, sizeof(_segments));
|
||||||
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
||||||
@ -656,6 +625,38 @@ void WS2812FX::resetSegments() {
|
|||||||
_segment_runtimes[0].reset();
|
_segment_runtimes[0].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WS2812FX::populateDefaultSegments() {
|
||||||
|
uint16_t length = 0;
|
||||||
|
if (autoSegments) {
|
||||||
|
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||||
|
Bus *bus = busses.getBus(i);
|
||||||
|
if (bus == nullptr) continue;
|
||||||
|
_segments[i].start = bus->getStart();
|
||||||
|
length += bus->getLength();
|
||||||
|
_segments[i].stop = _segments[i].start + bus->getLength();
|
||||||
|
_segments[i].mode = DEFAULT_MODE;
|
||||||
|
_segments[i].colors[0] = DEFAULT_COLOR;
|
||||||
|
_segments[i].speed = DEFAULT_SPEED;
|
||||||
|
_segments[i].intensity = DEFAULT_INTENSITY;
|
||||||
|
_segments[i].grouping = 1;
|
||||||
|
_segments[i].setOption(SEG_OPTION_SELECTED, 1);
|
||||||
|
_segments[i].setOption(SEG_OPTION_ON, 1);
|
||||||
|
_segments[i].opacity = 255;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_segments[0].start = 0;
|
||||||
|
_segments[0].stop = _length;
|
||||||
|
_segments[0].mode = DEFAULT_MODE;
|
||||||
|
_segments[0].colors[0] = DEFAULT_COLOR;
|
||||||
|
_segments[0].speed = DEFAULT_SPEED;
|
||||||
|
_segments[0].intensity = DEFAULT_INTENSITY;
|
||||||
|
_segments[0].grouping = 1;
|
||||||
|
_segments[0].setOption(SEG_OPTION_SELECTED, 1);
|
||||||
|
_segments[0].setOption(SEG_OPTION_ON, 1);
|
||||||
|
_segments[0].opacity = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
|
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
|
||||||
void WS2812FX::setPixelSegment(uint8_t n)
|
void WS2812FX::setPixelSegment(uint8_t n)
|
||||||
{
|
{
|
||||||
@ -1033,18 +1034,33 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8
|
|||||||
|
|
||||||
|
|
||||||
//load custom mapping table from JSON file
|
//load custom mapping table from JSON file
|
||||||
void WS2812FX::deserializeMap(void) {
|
void WS2812FX::deserializeMap(uint8_t n) {
|
||||||
if (!WLED_FS.exists("/ledmap.json")) return;
|
String fileName = String(F("/ledmap"));
|
||||||
|
if (n) fileName += String(n);
|
||||||
|
fileName += String(F(".json"));
|
||||||
|
bool isFile = WLED_FS.exists(fileName);
|
||||||
|
|
||||||
|
if (!isFile) {
|
||||||
|
// erase custom mapping if selecting nonexistent ledmap.json (n==0)
|
||||||
|
if (!n && customMappingTable != nullptr) {
|
||||||
|
customMappingSize = 0;
|
||||||
|
delete[] customMappingTable;
|
||||||
|
customMappingTable = nullptr;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE); // full sized buffer for larger maps
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE); // full sized buffer for larger maps
|
||||||
|
DEBUG_PRINT(F("Reading LED map from "));
|
||||||
|
DEBUG_PRINTLN(fileName);
|
||||||
|
|
||||||
DEBUG_PRINTLN(F("Reading LED map from /ledmap.json..."));
|
if (!readObjectFromFile(fileName.c_str(), nullptr, &doc)) return; //if file does not exist just exit
|
||||||
|
|
||||||
if (!readObjectFromFile("/ledmap.json", nullptr, &doc)) return; //if file does not exist just exit
|
|
||||||
|
|
||||||
|
// erase old custom ledmap
|
||||||
if (customMappingTable != nullptr) {
|
if (customMappingTable != nullptr) {
|
||||||
|
customMappingSize = 0;
|
||||||
delete[] customMappingTable;
|
delete[] customMappingTable;
|
||||||
customMappingTable = nullptr;
|
customMappingTable = nullptr;
|
||||||
customMappingSize = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray map = doc[F("map")];
|
JsonArray map = doc[F("map")];
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
#ifndef WLED_DISABLE_BLYNK
|
||||||
#include "src/dependencies/blynk/Blynk/BlynkHandlers.h"
|
#include "src/dependencies/blynk/Blynk/BlynkHandlers.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remote light control with the free Blynk app
|
* Remote light control with the free Blynk app
|
||||||
|
@ -10,18 +10,24 @@
|
|||||||
#include "bus_wrapper.h"
|
#include "bus_wrapper.h"
|
||||||
#include <Arduino.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
|
//temporary struct for passing bus configuration to bus
|
||||||
struct BusConfig {
|
struct BusConfig {
|
||||||
uint8_t type = TYPE_WS2812_RGB;
|
uint8_t type = TYPE_WS2812_RGB;
|
||||||
uint16_t count = 1;
|
uint16_t count;
|
||||||
uint16_t start = 0;
|
uint16_t start;
|
||||||
uint8_t colorOrder = COL_ORDER_GRB;
|
uint8_t colorOrder;
|
||||||
bool reversed = false;
|
bool reversed;
|
||||||
uint8_t skipAmount;
|
uint8_t skipAmount;
|
||||||
|
bool rgbwOverride;
|
||||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip=0) {
|
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0) {
|
||||||
type = busType; count = len; start = pstart;
|
rgbwOverride = (bool) GET_BIT(busType,7);
|
||||||
colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
|
type = busType & 0x7F; // bit 7 may be/is hacked to include RGBW info (1=RGBW, 0=RGB)
|
||||||
|
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
|
||||||
uint8_t nPins = 1;
|
uint8_t nPins = 1;
|
||||||
if (type > 47) nPins = 2;
|
if (type > 47) nPins = 2;
|
||||||
else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
|
else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||||
@ -74,7 +80,7 @@ class Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual uint16_t getLength() {
|
virtual uint16_t getLength() {
|
||||||
return 1;
|
return 1; // is this ok? shouldn't it be 0 in virtual function?
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setColorOrder() {}
|
virtual void setColorOrder() {}
|
||||||
@ -130,12 +136,12 @@ class BusDigital : public Bus {
|
|||||||
reversed = bc.reversed;
|
reversed = bc.reversed;
|
||||||
_skip = bc.skipAmount; //sacrificial pixels
|
_skip = bc.skipAmount; //sacrificial pixels
|
||||||
_len = bc.count + _skip;
|
_len = bc.count + _skip;
|
||||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
_rgbw = bc.rgbwOverride || Bus::isRgbw(bc.type); // RGBW override in bit 7
|
||||||
|
_iType = PolyBus::getI(bc.type, _pins, nr, _rgbw);
|
||||||
if (_iType == I_NONE) return;
|
if (_iType == I_NONE) return;
|
||||||
_busPtr = PolyBus::create(_iType, _pins, _len, nr);
|
_busPtr = PolyBus::create(_iType, _pins, _len, nr);
|
||||||
_valid = (_busPtr != nullptr);
|
_valid = (_busPtr != nullptr);
|
||||||
_colorOrder = bc.colorOrder;
|
_colorOrder = bc.colorOrder;
|
||||||
//Serial.printf("Successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n",nr, len, type, pins[0],pins[1],_iType);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void show() {
|
inline void show() {
|
||||||
@ -189,7 +195,7 @@ class BusDigital : public Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool isRgbw() {
|
inline bool isRgbw() {
|
||||||
return (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814);
|
return (_rgbw || _type == TYPE_SK6812_RGBW || _type == TYPE_TM1814);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t skippedLeds() {
|
inline uint8_t skippedLeds() {
|
||||||
@ -201,7 +207,6 @@ class BusDigital : public Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cleanup() {
|
void cleanup() {
|
||||||
//Serial.println("Digital Cleanup");
|
|
||||||
PolyBus::cleanup(_busPtr, _iType);
|
PolyBus::cleanup(_busPtr, _iType);
|
||||||
_iType = I_NONE;
|
_iType = I_NONE;
|
||||||
_valid = false;
|
_valid = false;
|
||||||
@ -220,6 +225,7 @@ class BusDigital : public Bus {
|
|||||||
uint8_t _iType = I_NONE;
|
uint8_t _iType = I_NONE;
|
||||||
uint16_t _len = 0;
|
uint16_t _len = 0;
|
||||||
uint8_t _skip = 0;
|
uint8_t _skip = 0;
|
||||||
|
bool _rgbw = false;
|
||||||
void * _busPtr = nullptr;
|
void * _busPtr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -227,6 +233,7 @@ class BusDigital : public Bus {
|
|||||||
class BusPwm : public Bus {
|
class BusPwm : public Bus {
|
||||||
public:
|
public:
|
||||||
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) {
|
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) {
|
||||||
|
_valid = false;
|
||||||
if (!IS_PWM(bc.type)) return;
|
if (!IS_PWM(bc.type)) return;
|
||||||
uint8_t numPins = NUM_PWM_PINS(bc.type);
|
uint8_t numPins = NUM_PWM_PINS(bc.type);
|
||||||
|
|
||||||
@ -280,10 +287,12 @@ class BusPwm : public Bus {
|
|||||||
|
|
||||||
//does no index check
|
//does no index check
|
||||||
uint32_t getPixelColor(uint16_t pix) {
|
uint32_t getPixelColor(uint16_t pix) {
|
||||||
|
if (!_valid) return 0;
|
||||||
return ((_data[3] << 24) | (_data[0] << 16) | (_data[1] << 8) | (_data[2]));
|
return ((_data[3] << 24) | (_data[0] << 16) | (_data[1] << 8) | (_data[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void show() {
|
void show() {
|
||||||
|
if (!_valid) return;
|
||||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||||
for (uint8_t i = 0; i < numPins; i++) {
|
for (uint8_t i = 0; i < numPins; i++) {
|
||||||
uint8_t scaled = (_data[i] * _bri) / 255;
|
uint8_t scaled = (_data[i] * _bri) / 255;
|
||||||
@ -302,7 +311,9 @@ class BusPwm : public Bus {
|
|||||||
|
|
||||||
uint8_t getPins(uint8_t* pinArray) {
|
uint8_t getPins(uint8_t* pinArray) {
|
||||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
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;
|
return numPins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,13 +339,13 @@ class BusPwm : public Bus {
|
|||||||
void deallocatePins() {
|
void deallocatePins() {
|
||||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||||
for (uint8_t i = 0; i < numPins; i++) {
|
for (uint8_t i = 0; i < numPins; i++) {
|
||||||
|
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm);
|
||||||
if (!pinManager.isPinOk(_pins[i])) continue;
|
if (!pinManager.isPinOk(_pins[i])) continue;
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
|
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
|
||||||
#else
|
#else
|
||||||
if (_ledcStart < 16) ledcDetachPin(_pins[i]);
|
if (_ledcStart < 16) ledcDetachPin(_pins[i]);
|
||||||
#endif
|
#endif
|
||||||
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm);
|
|
||||||
}
|
}
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
pinManager.deallocateLedc(_ledcStart, numPins);
|
pinManager.deallocateLedc(_ledcStart, numPins);
|
||||||
@ -342,6 +353,86 @@ class BusPwm : public Bus {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BusVirtual : public Bus {
|
||||||
|
public:
|
||||||
|
BusVirtual(BusConfig &bc) : Bus(bc.type, bc.start) {
|
||||||
|
_valid = false;
|
||||||
|
_data = (byte *)malloc(bc.count * (_rgbw ? 4 : 3));
|
||||||
|
if (_data == nullptr) return;
|
||||||
|
memset(_data, 0, bc.count * (_rgbw ? 4 : 3));
|
||||||
|
_len = bc.count;
|
||||||
|
//_rgbw = bc.rgbwOverride; // RGBW override in bit 7 or can have a special type
|
||||||
|
_rgbw = _type == TYPE_VIRTUAL_RGBW;
|
||||||
|
_colorOrder = bc.colorOrder;
|
||||||
|
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
|
||||||
|
_broadcastLock = false;
|
||||||
|
_valid = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setPixelColor(uint16_t pix, uint32_t c) {
|
||||||
|
if (!_valid || pix >= _len) return;
|
||||||
|
_data[pix] = 0xFF & (c >> 16);
|
||||||
|
_data[pix+1] = 0xFF & (c >> 8);
|
||||||
|
_data[pix+2] = 0xFF & (c );
|
||||||
|
if (_rgbw) _data[pix+3] = 0xFF & (c >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getPixelColor(uint16_t pix) {
|
||||||
|
if (!_valid || pix >= _len) return 0;
|
||||||
|
return ((_rgbw?(_data[pix+3] << 24):0) | (_data[pix] << 16) | (_data[pix+1] << 8) | (_data[pix+2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void show() {
|
||||||
|
if (!_valid || _broadcastLock) return;
|
||||||
|
_broadcastLock = true;
|
||||||
|
realtimeBoroadcast(_client, _len, _data, _rgbw);
|
||||||
|
_broadcastLock = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool canShow() {
|
||||||
|
return !_broadcastLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setBrightness(uint8_t b) {
|
||||||
|
// not sure if this is correctly implemented
|
||||||
|
for (uint16_t pix=0; pix<_len; pix++) {
|
||||||
|
_data[pix ] = scale8(_data[pix ], b);
|
||||||
|
_data[pix+1] = scale8(_data[pix+1], b);
|
||||||
|
_data[pix+2] = scale8(_data[pix+2], b);
|
||||||
|
if (_rgbw) _data[pix+3] = scale8(_data[pix+3], b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isRgbw() {
|
||||||
|
return _rgbw;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t getLength() {
|
||||||
|
return _len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() {
|
||||||
|
_type = I_NONE;
|
||||||
|
_valid = false;
|
||||||
|
if (_data != nullptr) free(_data);
|
||||||
|
_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~BusVirtual() {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IPAddress _client;
|
||||||
|
uint16_t _len = 0;
|
||||||
|
uint8_t _colorOrder;
|
||||||
|
bool _rgbw;
|
||||||
|
bool _broadcastLock;
|
||||||
|
byte* _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class BusManager {
|
class BusManager {
|
||||||
public:
|
public:
|
||||||
BusManager() {
|
BusManager() {
|
||||||
@ -352,7 +443,9 @@ class BusManager {
|
|||||||
static uint32_t memUsage(BusConfig &bc) {
|
static uint32_t memUsage(BusConfig &bc) {
|
||||||
uint8_t type = bc.type;
|
uint8_t type = bc.type;
|
||||||
uint16_t len = bc.count;
|
uint16_t len = bc.count;
|
||||||
if (type < 32) {
|
if (type < 4) {
|
||||||
|
return len * (type+1);
|
||||||
|
} else if (type < 32) {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
|
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
|
||||||
if (type > 29) return len*20; //RGBW
|
if (type > 29) return len*20; //RGBW
|
||||||
@ -373,7 +466,9 @@ class BusManager {
|
|||||||
|
|
||||||
int add(BusConfig &bc) {
|
int add(BusConfig &bc) {
|
||||||
if (numBusses >= WLED_MAX_BUSSES) return -1;
|
if (numBusses >= WLED_MAX_BUSSES) return -1;
|
||||||
if (IS_DIGITAL(bc.type)) {
|
if (bc.type>1 && bc.type<4) {
|
||||||
|
busses[numBusses] = new BusVirtual(bc);
|
||||||
|
} else if (IS_DIGITAL(bc.type)) {
|
||||||
busses[numBusses] = new BusDigital(bc, numBusses);
|
busses[numBusses] = new BusDigital(bc, numBusses);
|
||||||
} else {
|
} else {
|
||||||
busses[numBusses] = new BusPwm(bc);
|
busses[numBusses] = new BusPwm(bc);
|
||||||
@ -444,6 +539,7 @@ class BusManager {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a workaround
|
||||||
static inline bool isRgbw(uint8_t type) {
|
static inline bool isRgbw(uint8_t type) {
|
||||||
return Bus::isRgbw(type);
|
return Bus::isRgbw(type);
|
||||||
}
|
}
|
||||||
|
@ -383,11 +383,6 @@ class PolyBus {
|
|||||||
uint8_t w = c >> 24;
|
uint8_t w = c >> 24;
|
||||||
RgbwColor col;
|
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
|
//reorder channels to selected order
|
||||||
switch (co)
|
switch (co)
|
||||||
{
|
{
|
||||||
@ -559,10 +554,6 @@ class PolyBus {
|
|||||||
case I_SS_P98_3: col = (static_cast<B_SS_P98_3*>(busPtr))->GetPixelColor(pix); break;
|
case I_SS_P98_3: col = (static_cast<B_SS_P98_3*>(busPtr))->GetPixelColor(pix); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COLOR_ORDER_OVERRIDE
|
|
||||||
if (pix >= COO_MIN && pix < COO_MAX) co = COO_ORDER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (co)
|
switch (co)
|
||||||
{
|
{
|
||||||
// W G R B
|
// W G R B
|
||||||
@ -632,14 +623,17 @@ class PolyBus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//gives back the internal type index (I_XX_XXX_X above) for the input
|
//gives back the internal type index (I_XX_XXX_X above) for the input
|
||||||
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) {
|
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0, bool isRGBW = false) {
|
||||||
if (!IS_DIGITAL(busType)) return I_NONE;
|
if (!IS_DIGITAL(busType)) return I_NONE;
|
||||||
if (IS_2PIN(busType)) { //SPI LED chips
|
if (IS_2PIN(busType)) { //SPI LED chips
|
||||||
bool isHSPI = false;
|
bool isHSPI = false;
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
if (pins[0] == P_8266_HS_MOSI && pins[1] == P_8266_HS_CLK) isHSPI = true;
|
if (pins[0] == P_8266_HS_MOSI && pins[1] == P_8266_HS_CLK) isHSPI = true;
|
||||||
#else
|
#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
|
#endif
|
||||||
uint8_t t = I_NONE;
|
uint8_t t = I_NONE;
|
||||||
switch (busType) {
|
switch (busType) {
|
||||||
@ -658,9 +652,8 @@ class PolyBus {
|
|||||||
switch (busType) {
|
switch (busType) {
|
||||||
case TYPE_WS2812_RGB:
|
case TYPE_WS2812_RGB:
|
||||||
case TYPE_WS2812_WWA:
|
case TYPE_WS2812_WWA:
|
||||||
return I_8266_U0_NEO_3 + offset;
|
|
||||||
case TYPE_SK6812_RGBW:
|
case TYPE_SK6812_RGBW:
|
||||||
return I_8266_U0_NEO_4 + offset;
|
return (isRGBW ? I_8266_U0_NEO_4 : I_8266_U0_NEO_3) + offset;
|
||||||
case TYPE_WS2811_400KHZ:
|
case TYPE_WS2811_400KHZ:
|
||||||
return I_8266_U0_400_3 + offset;
|
return I_8266_U0_400_3 + offset;
|
||||||
case TYPE_TM1814:
|
case TYPE_TM1814:
|
||||||
@ -678,9 +671,10 @@ class PolyBus {
|
|||||||
switch (busType) {
|
switch (busType) {
|
||||||
case TYPE_WS2812_RGB:
|
case TYPE_WS2812_RGB:
|
||||||
case TYPE_WS2812_WWA:
|
case TYPE_WS2812_WWA:
|
||||||
return I_32_RN_NEO_3 + offset;
|
// return I_32_RN_NEO_3 + offset;
|
||||||
case TYPE_SK6812_RGBW:
|
case TYPE_SK6812_RGBW:
|
||||||
return I_32_RN_NEO_4 + offset;
|
// return I_32_RN_NEO_4 + offset;
|
||||||
|
return (isRGBW ? I_32_RN_NEO_4 : I_32_RN_NEO_3) + offset;
|
||||||
case TYPE_WS2811_400KHZ:
|
case TYPE_WS2811_400KHZ:
|
||||||
return I_32_RN_400_3 + offset;
|
return I_32_RN_400_3 + offset;
|
||||||
case TYPE_TM1814:
|
case TYPE_TM1814:
|
||||||
|
@ -10,10 +10,11 @@ static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize fl
|
|||||||
|
|
||||||
void shortPressAction(uint8_t b)
|
void shortPressAction(uint8_t b)
|
||||||
{
|
{
|
||||||
if (!macroButton[b])
|
if (!macroButton[b]) {
|
||||||
{
|
switch (b) {
|
||||||
toggleOnOff();
|
case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||||
colorUpdated(CALL_MODE_BUTTON);
|
default: ++effectCurrent %= strip.getModeCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
applyPreset(macroButton[b], CALL_MODE_BUTTON);
|
applyPreset(macroButton[b], CALL_MODE_BUTTON);
|
||||||
}
|
}
|
||||||
@ -26,6 +27,44 @@ void shortPressAction(uint8_t b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void longPressAction(uint8_t b)
|
||||||
|
{
|
||||||
|
if (!macroLongPress[b]) {
|
||||||
|
switch (b) {
|
||||||
|
case 0: _setRandomColor(false,true); break;
|
||||||
|
default: bri += 8; colorUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
applyPreset(macroLongPress[b], CALL_MODE_BUTTON);
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish MQTT message
|
||||||
|
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||||
|
char subuf[64];
|
||||||
|
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||||
|
mqtt->publish(subuf, 0, false, "long");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void doublePressAction(uint8_t b)
|
||||||
|
{
|
||||||
|
if (!macroDoublePress[b]) {
|
||||||
|
switch (b) {
|
||||||
|
case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||||
|
default: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON);
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish MQTT message
|
||||||
|
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||||
|
char subuf[64];
|
||||||
|
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||||
|
mqtt->publish(subuf, 0, false, "double");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isButtonPressed(uint8_t i)
|
bool isButtonPressed(uint8_t i)
|
||||||
{
|
{
|
||||||
if (btnPin[i]<0) return false;
|
if (btnPin[i]<0) return false;
|
||||||
@ -186,61 +225,43 @@ void handleButton()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//momentary button logic
|
//momentary button logic
|
||||||
if (isButtonPressed(b)) //pressed
|
if (isButtonPressed(b)) { //pressed
|
||||||
{
|
|
||||||
if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis();
|
if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis();
|
||||||
buttonPressedBefore[b] = true;
|
buttonPressedBefore[b] = true;
|
||||||
|
|
||||||
if (millis() - buttonPressedTime[b] > 600) //long press
|
if (millis() - buttonPressedTime[b] > 600) { //long press
|
||||||
{
|
if (!buttonLongPressed[b]) longPressAction(b);
|
||||||
if (!buttonLongPressed[b])
|
else if (b) { // repeatable action (~3 times per s) on button > 0
|
||||||
{
|
longPressAction(b);
|
||||||
if (macroLongPress[b]) {applyPreset(macroLongPress[b], CALL_MODE_BUTTON);}
|
buttonPressedTime[b] = millis() - 300; // 300ms
|
||||||
else _setRandomColor(false,true);
|
|
||||||
|
|
||||||
// publish MQTT message
|
|
||||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
|
||||||
char subuf[64];
|
|
||||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
|
||||||
mqtt->publish(subuf, 0, false, "long");
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonLongPressed[b] = true;
|
|
||||||
}
|
}
|
||||||
|
buttonLongPressed[b] = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (!isButtonPressed(b) && buttonPressedBefore[b]) //released
|
} else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released
|
||||||
{
|
|
||||||
long dur = millis() - buttonPressedTime[b];
|
long dur = millis() - buttonPressedTime[b];
|
||||||
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
|
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
|
||||||
bool doublePress = buttonWaitTime[b];
|
bool doublePress = buttonWaitTime[b]; //did we have short press before?
|
||||||
buttonWaitTime[b] = 0;
|
buttonWaitTime[b] = 0;
|
||||||
|
|
||||||
if (dur > 6000 && b==0) //long press on button 0
|
if (b == 0 && dur > 6000) { //long press on button 0 (when released)
|
||||||
{
|
|
||||||
WLED::instance().initAP(true);
|
WLED::instance().initAP(true);
|
||||||
}
|
} else if (!buttonLongPressed[b]) { //short press
|
||||||
else if (!buttonLongPressed[b]) { //short press
|
// if this is second release within 350ms it is a double press (buttonWaitTime!=0)
|
||||||
if (macroDoublePress[b])
|
if (doublePress) {
|
||||||
{
|
doublePressAction(b);
|
||||||
if (doublePress) {
|
} else {
|
||||||
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON);
|
buttonWaitTime[b] = millis();
|
||||||
|
}
|
||||||
// publish MQTT message
|
|
||||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
|
||||||
char subuf[64];
|
|
||||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
|
||||||
mqtt->publish(subuf, 0, false, "double");
|
|
||||||
}
|
|
||||||
} else buttonWaitTime[b] = millis();
|
|
||||||
} else shortPressAction(b);
|
|
||||||
}
|
}
|
||||||
buttonPressedBefore[b] = false;
|
buttonPressedBefore[b] = false;
|
||||||
buttonLongPressed[b] = false;
|
buttonLongPressed[b] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 450 && !buttonPressedBefore[b])
|
// if 450ms elapsed since last press/release it is a short press
|
||||||
{
|
if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) {
|
||||||
buttonWaitTime[b] = 0;
|
buttonWaitTime[b] = 0;
|
||||||
shortPressAction(b);
|
shortPressAction(b);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
#include "wled_ethernet.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS.
|
* Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS.
|
||||||
@ -29,6 +30,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
getStringFromJson(cmDNS, id[F("mdns")], 33);
|
getStringFromJson(cmDNS, id[F("mdns")], 33);
|
||||||
getStringFromJson(serverDescription, id[F("name")], 33);
|
getStringFromJson(serverDescription, id[F("name")], 33);
|
||||||
getStringFromJson(alexaInvocationName, id[F("inv")], 33);
|
getStringFromJson(alexaInvocationName, id[F("inv")], 33);
|
||||||
|
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||||
|
CJSON(simplifiedUI, id[F("sui")]);
|
||||||
|
#endif
|
||||||
|
|
||||||
JsonObject nw_ins_0 = doc["nw"]["ins"][0];
|
JsonObject nw_ins_0 = doc["nw"]["ins"][0];
|
||||||
getStringFromJson(clientSSID, nw_ins_0[F("ssid")], 33);
|
getStringFromJson(clientSSID, nw_ins_0[F("ssid")], 33);
|
||||||
@ -60,7 +64,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
|
|
||||||
CJSON(apBehavior, ap[F("behav")]);
|
CJSON(apBehavior, ap[F("behav")]);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
JsonArray ap_ip = ap["ip"];
|
JsonArray ap_ip = ap["ip"];
|
||||||
for (byte i = 0; i < 4; i++) {
|
for (byte i = 0; i < 4; i++) {
|
||||||
@ -79,16 +82,16 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
|
|
||||||
CJSON(ledCount, hw_led[F("total")]);
|
CJSON(ledCount, hw_led[F("total")]);
|
||||||
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
||||||
|
uint16_t lC = 0;
|
||||||
|
|
||||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
||||||
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
|
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
|
||||||
|
|
||||||
JsonArray ins = hw_led["ins"];
|
JsonArray ins = hw_led["ins"];
|
||||||
|
|
||||||
if (fromFS || !ins.isNull()) {
|
if (fromFS || !ins.isNull()) {
|
||||||
uint8_t s = 0; //bus iterator
|
uint8_t s = 0; // bus iterator
|
||||||
strip.isRgbw = false;
|
|
||||||
strip.isOffRefreshRequred = false;
|
|
||||||
busses.removeAll();
|
busses.removeAll();
|
||||||
uint32_t mem = 0;
|
uint32_t mem = 0;
|
||||||
for (JsonObject elm : ins) {
|
for (JsonObject elm : ins) {
|
||||||
@ -104,12 +107,20 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t length = elm[F("len")] | 1;
|
uint16_t length = elm[F("len")] | 1;
|
||||||
|
if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
|
||||||
uint8_t colorOrder = (int)elm[F("order")];
|
uint8_t colorOrder = (int)elm[F("order")];
|
||||||
uint8_t skipFirst = elm[F("skip")];
|
uint8_t skipFirst = elm[F("skip")];
|
||||||
uint16_t start = elm[F("start")] | 0;
|
uint16_t start = elm[F("start")] | 0;
|
||||||
|
if (start > lC+length) continue; // something is very wrong :)
|
||||||
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
|
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
|
||||||
bool reversed = elm["rev"];
|
bool reversed = elm["rev"];
|
||||||
|
//if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary)
|
||||||
|
s++;
|
||||||
|
lC += length;
|
||||||
|
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||||
|
mem += BusManager::memUsage(bc);
|
||||||
|
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
|
||||||
|
/*
|
||||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||||
if (bc.adjustBounds(ledCount)) {
|
if (bc.adjustBounds(ledCount)) {
|
||||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||||
@ -120,9 +131,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
mem += busses.memUsage(bc);
|
mem += busses.memUsage(bc);
|
||||||
if (mem <= MAX_LED_MEMORY) busses.add(bc);
|
if (mem <= MAX_LED_MEMORY) busses.add(bc);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
strip.finalizeInit(ledCount);
|
// finalization done in beginStrip()
|
||||||
}
|
}
|
||||||
|
if (lC > ledCount) ledCount = lC; // fix incorrect total length (honour analog setup)
|
||||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||||
|
|
||||||
// read multiple button configuration
|
// read multiple button configuration
|
||||||
@ -461,6 +474,7 @@ void serializeConfig() {
|
|||||||
id[F("mdns")] = cmDNS;
|
id[F("mdns")] = cmDNS;
|
||||||
id[F("name")] = serverDescription;
|
id[F("name")] = serverDescription;
|
||||||
id[F("inv")] = alexaInvocationName;
|
id[F("inv")] = alexaInvocationName;
|
||||||
|
id[F("sui")] = simplifiedUI;
|
||||||
|
|
||||||
JsonObject nw = doc.createNestedObject("nw");
|
JsonObject nw = doc.createNestedObject("nw");
|
||||||
|
|
||||||
@ -500,6 +514,25 @@ void serializeConfig() {
|
|||||||
#ifdef WLED_USE_ETHERNET
|
#ifdef WLED_USE_ETHERNET
|
||||||
JsonObject ethernet = doc.createNestedObject("eth");
|
JsonObject ethernet = doc.createNestedObject("eth");
|
||||||
ethernet["type"] = ethernetType;
|
ethernet["type"] = ethernetType;
|
||||||
|
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||||
|
JsonArray pins = ethernet.createNestedArray("pin");
|
||||||
|
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) pins.add(esp32_nonconfigurable_ethernet_pins[p].pin);
|
||||||
|
if (ethernetBoards[ethernetType].eth_power>=0) pins.add(ethernetBoards[ethernetType].eth_power);
|
||||||
|
if (ethernetBoards[ethernetType].eth_mdc>=0) pins.add(ethernetBoards[ethernetType].eth_mdc);
|
||||||
|
if (ethernetBoards[ethernetType].eth_mdio>=0) pins.add(ethernetBoards[ethernetType].eth_mdio);
|
||||||
|
switch (ethernetBoards[ethernetType].eth_clk_mode) {
|
||||||
|
case ETH_CLOCK_GPIO0_IN:
|
||||||
|
case ETH_CLOCK_GPIO0_OUT:
|
||||||
|
pins.add(0);
|
||||||
|
break;
|
||||||
|
case ETH_CLOCK_GPIO16_OUT:
|
||||||
|
pins.add(16);
|
||||||
|
break;
|
||||||
|
case ETH_CLOCK_GPIO17_OUT:
|
||||||
|
pins.add(17);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JsonObject hw = doc.createNestedObject("hw");
|
JsonObject hw = doc.createNestedObject("hw");
|
||||||
@ -526,6 +559,7 @@ void serializeConfig() {
|
|||||||
ins["rev"] = bus->reversed;
|
ins["rev"] = bus->reversed;
|
||||||
ins[F("skip")] = bus->skippedLeds();
|
ins[F("skip")] = bus->skippedLeds();
|
||||||
ins["type"] = bus->getType();
|
ins["type"] = bus->getType();
|
||||||
|
ins[F("rgbw")] = bus->isRgbw();
|
||||||
}
|
}
|
||||||
|
|
||||||
// button(s)
|
// button(s)
|
||||||
@ -550,7 +584,7 @@ void serializeConfig() {
|
|||||||
|
|
||||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||||
hw_ir["pin"] = irPin;
|
hw_ir["pin"] = irPin;
|
||||||
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||||
|
|
||||||
JsonObject hw_relay = hw.createNestedObject(F("relay"));
|
JsonObject hw_relay = hw.createNestedObject(F("relay"));
|
||||||
hw_relay["pin"] = rlyPin;
|
hw_relay["pin"] = rlyPin;
|
||||||
|
@ -122,6 +122,8 @@
|
|||||||
|
|
||||||
#define TYPE_NONE 0 //light is not configured
|
#define TYPE_NONE 0 //light is not configured
|
||||||
#define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light
|
#define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light
|
||||||
|
#define TYPE_VIRTUAL_RGB 2 //virtual RGB bus (master broadcast bus)
|
||||||
|
#define TYPE_VIRTUAL_RGBW 3 //virtual RGBW bus (master broadcast bus)
|
||||||
//Digital types (data pin only) (16-31)
|
//Digital types (data pin only) (16-31)
|
||||||
#define TYPE_WS2812_1CH 20 //white-only chips
|
#define TYPE_WS2812_1CH 20 //white-only chips
|
||||||
#define TYPE_WS2812_WWA 21 //amber + warm + cold white
|
#define TYPE_WS2812_WWA 21 //amber + warm + cold white
|
||||||
@ -233,7 +235,7 @@
|
|||||||
// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266
|
// 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
|
#ifndef MAX_LEDS
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define MAX_LEDS 1664 // can't rely on memory limit to limit this to 1600 LEDs
|
#define MAX_LEDS 1200 // can't rely on memory limit to limit this to 1200 LEDs
|
||||||
#else
|
#else
|
||||||
#define MAX_LEDS 8192
|
#define MAX_LEDS 8192
|
||||||
#endif
|
#endif
|
||||||
@ -241,14 +243,14 @@
|
|||||||
|
|
||||||
#ifndef MAX_LED_MEMORY
|
#ifndef MAX_LED_MEMORY
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define MAX_LED_MEMORY 5000
|
#define MAX_LED_MEMORY 4000
|
||||||
#else
|
#else
|
||||||
#define MAX_LED_MEMORY 64000
|
#define MAX_LED_MEMORY 64000
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MAX_LEDS_PER_BUS
|
#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
|
#endif
|
||||||
|
|
||||||
// string temp buffer (now stored in stack locally)
|
// string temp buffer (now stored in stack locally)
|
||||||
@ -282,7 +284,7 @@
|
|||||||
|
|
||||||
// Maximum size of node map (list of other WLED instances)
|
// Maximum size of node map (list of other WLED instances)
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define WLED_MAX_NODES 15
|
#define WLED_MAX_NODES 24
|
||||||
#else
|
#else
|
||||||
#define WLED_MAX_NODES 150
|
#define WLED_MAX_NODES 150
|
||||||
#endif
|
#endif
|
||||||
@ -304,8 +306,4 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DEFAULT_LED_COUNT
|
|
||||||
#define DEFAULT_LED_COUNT 30
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
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="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="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="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="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 id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button>
|
||||||
<button onclick="window.location.href = '/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
<button 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="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="briwrap">
|
<div id="briwrap">
|
||||||
<p class="hd">Brightness</p>
|
<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" />
|
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
||||||
<div class="sliderdisplay"></div>
|
<div class="sliderdisplay"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<iframe id="liveview" src="about:blank"></iframe>
|
<iframe id="liveview" src="about:blank"></iframe>
|
||||||
@ -46,17 +47,26 @@
|
|||||||
<div id="Colors" class="tabcontent">
|
<div id="Colors" class="tabcontent">
|
||||||
<div id="picker" class="noslide"></div>
|
<div id="picker" class="noslide"></div>
|
||||||
<div id="rgbwrap">
|
<div id="rgbwrap">
|
||||||
<div class="sliderwrap il">
|
<div id="rwrap" class="il">
|
||||||
<input id="sliderR" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,1)" max="255" min="0" type="range" value="128" />
|
<div class="sliderwrap il">
|
||||||
<div class="sliderdisplay"></div>
|
<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><br>
|
||||||
<div class="sliderwrap il">
|
<div id="gwrap" class="il">
|
||||||
<input id="sliderG" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,2)" max="255" min="0" type="range" value="128" />
|
<div class="sliderwrap il">
|
||||||
<div class="sliderdisplay"></div>
|
<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><br>
|
||||||
<div class="sliderwrap il">
|
<div id="bwrap" class="il">
|
||||||
<input id="sliderB" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,3)" max="255" min="0" type="range" value="128" />
|
<div class="sliderwrap il">
|
||||||
<div class="sliderdisplay"></div>
|
<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><br>
|
||||||
</div>
|
</div>
|
||||||
<div id="wwrap">
|
<div id="wwrap">
|
||||||
@ -64,6 +74,7 @@
|
|||||||
<div class="sliderwrap il">
|
<div class="sliderwrap il">
|
||||||
<input id="sliderW" class="noslide" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
<input id="sliderW" class="noslide" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||||
<div class="sliderdisplay"></div>
|
<div class="sliderdisplay"></div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="qcs-w">
|
<div id="qcs-w">
|
||||||
@ -77,28 +88,30 @@
|
|||||||
<div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
|
<div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
|
||||||
<div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
|
<div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
|
||||||
<div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
|
<div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
|
||||||
<div class="qcs" onclick="pC('rnd');" title="Random" style="background-color:var(--c-3); padding: 4px 8px; transform: translateY(-10px);">R</div>
|
<div class="qcs" onclick="pC('rnd');" title="Random" style="background:linear-gradient(to right, red, orange, yellow, green, blue, purple);transform: translateY(-11px);">R</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="csl">
|
<div id="csl">
|
||||||
<button class="xxs cl btn" onclick="selectSlot(0);">1</button>
|
<button class="btn xxs" onclick="selectSlot(0);">1</button>
|
||||||
<button class="xxs cl btn" onclick="selectSlot(1);">2</button>
|
<button class="btn xxs" onclick="selectSlot(1);">2</button>
|
||||||
<button class="xxs cl btn" onclick="selectSlot(2);">3</button>
|
<button class="btn xxs" onclick="selectSlot(2);">3</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="hexw">
|
<div id="hexw">
|
||||||
<input id="hexc" type="text" class="noslide" onkeydown="hexEnter(this)" autocomplete="off" maxlength="8" />
|
<input id="hexc" type="text" class="noslide" onkeydown="hexEnter(this)" autocomplete="off" maxlength="8" />
|
||||||
<button id="hexcnf" class="xxs btn" onclick="fromHex();"><i class="icons btna-icon"></i></button>
|
<button id="hexcnf" class="btn btn-xs" onclick="fromHex();"><i class="icons btn-icon"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<p class="labels">
|
<p class="labels"><i class="icons sel-icon" onclick="tglHex()"></i> Color palette</p>
|
||||||
<i class="icons sel-icon" onclick="tglHex()"></i>
|
|
||||||
Color palette
|
|
||||||
</p>
|
|
||||||
<div class="il">
|
<div class="il">
|
||||||
|
<div class="staytop fnd">
|
||||||
|
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pallist')" onfocus="search(this,'pallist')" />
|
||||||
|
<i class="icons clear-icon" onclick="clean(this)"></i>
|
||||||
|
<i class="icons search-icon"></i>
|
||||||
|
</div>
|
||||||
<div id="pallist" class="list">
|
<div id="pallist" class="list">
|
||||||
<div class="lstI" data-id="0">
|
<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()">
|
<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()">
|
||||||
<span class="checkmark schk"></span>
|
<span class="radiomark schk"></span>
|
||||||
</label>
|
</label>
|
||||||
<div class="lstIcontent">
|
<div class="lstIcontent">
|
||||||
<span class="lstIname">
|
<span class="lstIname">
|
||||||
@ -120,26 +133,33 @@
|
|||||||
|
|
||||||
<div id="Effects" class="tabcontent">
|
<div id="Effects" class="tabcontent">
|
||||||
<p class="labels">Effect speed</p>
|
<p class="labels">Effect speed</p>
|
||||||
<div class="staytop">
|
<div class="staytop" id="staytop">
|
||||||
<i class="icons slider-icon"></i>
|
<i class="icons slider-icon"></i>
|
||||||
<div class="sliderwrap il">
|
<div class="sliderwrap il">
|
||||||
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
<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 class="sliderdisplay"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
</div>
|
</div>
|
||||||
<p class="labels">Effect intensity</p>
|
<p class="labels">Effect intensity</p>
|
||||||
<div class="staytop" id="staytop1">
|
<div class="staytop" id="staytop1">
|
||||||
<i class="icons slider-icon" onclick="tglLabels()"></i>
|
<i class="icons slider-icon" onclick="tglLabels()"></i>
|
||||||
<div class="sliderwrap il">
|
<div class="sliderwrap il">
|
||||||
<input id="sliderIntensity" class="noslide" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
<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 class="sliderdisplay"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
</div>
|
</div>
|
||||||
<p class="labels">Effect mode</p>
|
<div class="il">
|
||||||
<div id="fxlist" class="list">
|
<p class="labels">Effect mode</p>
|
||||||
Loading...
|
<div class="staytop fnd" id="staytop2">
|
||||||
|
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this,'fxlist')" />
|
||||||
|
<i class="icons clear-icon" onclick="clean(this);"></i>
|
||||||
|
<i class="icons search-icon"></i>
|
||||||
|
</div>
|
||||||
|
<div id="fxlist" class="list">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -147,21 +167,18 @@
|
|||||||
<div id="segcont">
|
<div id="segcont">
|
||||||
Loading...
|
Loading...
|
||||||
</div>
|
</div>
|
||||||
<div id="segutil">
|
<div id="segutil" class="staybot">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="segutil2">
|
<div id="segutil2">
|
||||||
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
||||||
</div>
|
</div>
|
||||||
<p>Transition: <input id="tt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s</p>
|
<!--p>Transition: <input id="tt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s</p-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="Presets" class="tabcontent">
|
<div id="Presets" class="tabcontent">
|
||||||
<div id="putil">
|
<div id="putil" class="staytop">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="pql">
|
<div id="pql">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="pcont">
|
<div id="pcont">
|
||||||
Loading...
|
Loading...
|
||||||
@ -183,19 +200,19 @@
|
|||||||
<div id="imgw">
|
<div id="imgw">
|
||||||
<img class="wi" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAFCAYAAAC5Fuf5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABbSURBVChTlY9bDoAwDMNW7n9nwCipytQN4Z8tbrTHmDmF4oPzyldwRqp1SSdnV/NuZuzqerAByxXznBw3igkeFEfXyUuhK/yFM0CxJfyqXZEOc6/Sr9/bf7uIC5Nwd7orMvAPAAAAAElFTkSuQmCC" />
|
<img class="wi" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAFCAYAAAC5Fuf5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABbSURBVChTlY9bDoAwDMNW7n9nwCipytQN4Z8tbrTHmDmF4oPzyldwRqp1SSdnV/NuZuzqerAByxXznBw3igkeFEfXyUuhK/yFM0CxJfyqXZEOc6/Sr9/bf7uIC5Nwd7orMvAPAAAAAElFTkSuQmCC" />
|
||||||
</div><br>
|
</div><br>
|
||||||
<div id="kv">Loading...</div><br>
|
<div id="kv">Loading...</div><br>
|
||||||
<button class="btn infobtn" onclick="requestJson(null)">Refresh</button>
|
<button class="btn infobtn" onclick="loadInfo()">Refresh</button>
|
||||||
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
||||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
|
<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>
|
<span class="h">Made with <span id="heart">❤︎</span> by Aircoookie and the WLED community</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="nodes" class="modal">
|
<div id="nodes" class="modal">
|
||||||
<div id="ndlt">WLED instances</div>
|
<div id="ndlt">WLED instances</div>
|
||||||
<div id="kn">Loading...</div><br>
|
<div id="kn">Loading...</div><br>
|
||||||
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
|
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
|
||||||
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
|
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="rover" class="modal">
|
<div id="rover" class="modal">
|
||||||
|
1977
wled00/data/index.js
1977
wled00/data/index.js
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
|||||||
background: #333;
|
background: #333;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-family: Verdana, Helvetica, sans-serif;
|
font-family: Verdana, Helvetica, sans-serif;
|
||||||
|
display: inline-block;
|
||||||
border: 1px solid #333;
|
border: 1px solid #333;
|
||||||
font-size: 6vmin;
|
font-size: 6vmin;
|
||||||
height: var(--h);
|
height: var(--h);
|
||||||
|
@ -31,14 +31,14 @@ function mMap(){
|
|||||||
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}
|
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}
|
||||||
function GetV(){}
|
function GetV(){}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>@import url("/style.css");</style>
|
||||||
@import url("style.css");
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body onload="S()">
|
<body onload="S()">
|
||||||
<form id="form_s" name="Sf" method="post">
|
<form id="form_s" name="Sf" method="post">
|
||||||
|
<div class="toprow">
|
||||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
<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 //-->
|
<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>
|
Proxy Universe <input name=PU type=number min=0 max=63999 required> from E1.31 to DMX (0=disabled)<br>
|
||||||
|
@ -1,436 +1,478 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=500">
|
<meta name="viewport" content="width=500">
|
||||||
<title>LED Settings</title>
|
<title>LED Settings</title>
|
||||||
<script>
|
<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
|
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()
|
function H()
|
||||||
{
|
{
|
||||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");
|
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");
|
||||||
}
|
}
|
||||||
function B()
|
function B()
|
||||||
{
|
{
|
||||||
window.open("/settings","_self");
|
window.open("/settings","_self");
|
||||||
}
|
}
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
function off(n){
|
function off(n){
|
||||||
d.getElementsByName(n)[0].value = -1;
|
d.getElementsByName(n)[0].value = -1;
|
||||||
}
|
}
|
||||||
var timeout;
|
var timeout;
|
||||||
function showToast(text, error = false)
|
function showToast(text, error = false)
|
||||||
{
|
{
|
||||||
var x = gId("toast");
|
var x = gId("toast");
|
||||||
x.innerHTML = text;
|
x.innerHTML = text;
|
||||||
x.className = error ? "error":"show";
|
x.className = error ? "error":"show";
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
x.style.animation = 'none';
|
x.style.animation = 'none';
|
||||||
timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900);
|
timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900);
|
||||||
}
|
}
|
||||||
function bLimits(b,p,m) {
|
function bLimits(b,p,m) {
|
||||||
maxB = b; maxM = m; maxPB = p;
|
maxB = b; maxM = m; maxPB = p;
|
||||||
}
|
}
|
||||||
function pinsOK() {
|
function pinsOK() {
|
||||||
var LCs = d.getElementsByTagName("input");
|
var LCs = d.getElementsByTagName("input");
|
||||||
for (i=0; i<LCs.length; i++) {
|
for (i=0; i<LCs.length; i++) {
|
||||||
var nm = LCs[i].name.substring(0,2);
|
var nm = LCs[i].name.substring(0,2);
|
||||||
//check for pin conflicts
|
//check for pin conflicts
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
||||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
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;}
|
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.um_p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;}
|
||||||
else if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].value="";LCs[i].focus();return false;}
|
else if (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++)
|
else if (!(nm == "IR" || nm=="BT") && LCs[i].value > 33) {alert("Sorry, pins >33 are input only.");LCs[i].value="";LCs[i].focus();return false;}
|
||||||
{
|
for (j=i+1; j<LCs.length; j++)
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
{
|
||||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
|
var n2 = LCs[j].name.substring(0,2);
|
||||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${nm}/${n2}!`);LCs[j].value="";LCs[j].focus();return false;}
|
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
|
||||||
}
|
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);LCs[j].value="";LCs[j].focus();return false;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
}
|
return true;
|
||||||
function trySubmit(e) {
|
}
|
||||||
e.preventDefault();
|
function trySubmit(e) {
|
||||||
if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server
|
d.Sf.data.value = '';
|
||||||
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
|
e.preventDefault();
|
||||||
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
|
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);}
|
||||||
function S(){GetV();setABL();}
|
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
|
||||||
function enABL()
|
}
|
||||||
{
|
function S(){GetV();setABL();}
|
||||||
var en = gId('able').checked;
|
function enABL()
|
||||||
d.Sf.LA.value = (en) ? laprev:0;
|
{
|
||||||
gId('abl').style.display = (en) ? 'inline':'none';
|
var en = gId('able').checked;
|
||||||
gId('psu2').style.display = (en) ? 'inline':'none';
|
d.Sf.LA.value = (en) ? laprev:0;
|
||||||
if (d.Sf.LA.value > 0) setABL();
|
gId('abl').style.display = (en) ? 'inline':'none';
|
||||||
}
|
gId('psu2').style.display = (en) ? 'inline':'none';
|
||||||
function enLA()
|
if (d.Sf.LA.value > 0) setABL();
|
||||||
{
|
}
|
||||||
var val = d.Sf.LAsel.value;
|
function enLA()
|
||||||
d.Sf.LA.value = val;
|
{
|
||||||
gId('LAdis').style.display = (val == 50) ? 'inline':'none';
|
var val = d.Sf.LAsel.value;
|
||||||
UI();
|
d.Sf.LA.value = val;
|
||||||
}
|
gId('LAdis').style.display = (val == 50) ? 'inline':'none';
|
||||||
function setABL()
|
UI();
|
||||||
{
|
}
|
||||||
gId('able').checked = true;
|
function setABL()
|
||||||
d.Sf.LAsel.value = 50;
|
{
|
||||||
switch (parseInt(d.Sf.LA.value)) {
|
gId('able').checked = true;
|
||||||
case 0: gId('able').checked = false; enABL(); break;
|
d.Sf.LAsel.value = 50;
|
||||||
case 30: d.Sf.LAsel.value = 30; break;
|
switch (parseInt(d.Sf.LA.value)) {
|
||||||
case 35: d.Sf.LAsel.value = 35; break;
|
case 0: gId('able').checked = false; enABL(); break;
|
||||||
case 55: d.Sf.LAsel.value = 55; break;
|
case 30: d.Sf.LAsel.value = 30; break;
|
||||||
case 255: d.Sf.LAsel.value = 255; break;
|
case 35: d.Sf.LAsel.value = 35; break;
|
||||||
default: gId('LAdis').style.display = 'inline';
|
case 55: d.Sf.LAsel.value = 55; break;
|
||||||
}
|
case 255: d.Sf.LAsel.value = 255; break;
|
||||||
gId('m1').innerHTML = maxM;
|
default: gId('LAdis').style.display = 'inline';
|
||||||
d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
|
}
|
||||||
UI();
|
gId('m1').innerHTML = maxM;
|
||||||
}
|
d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
|
||||||
//returns mem usage
|
UI();
|
||||||
function getMem(type, len, p0) {
|
}
|
||||||
if (type < 32) {
|
//returns mem usage
|
||||||
if (maxM < 10000 && p0==3) { //8266 DMA uses 5x the mem
|
function getMem(type, len, p0) {
|
||||||
if (type > 29) return len*20; //RGBW
|
if (type < 32) {
|
||||||
return len*15;
|
if (maxM < 10000 && p0==3) { //8266 DMA uses 5x the mem
|
||||||
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
if (type > 29) return len*20; //RGBW
|
||||||
{
|
return len*15;
|
||||||
if (type > 29) return len*8; //RGBW
|
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
||||||
return len*6;
|
{
|
||||||
}
|
if (type > 29) return len*8; //RGBW
|
||||||
if (type > 29) return len*4; //RGBW
|
return len*6;
|
||||||
return len*3;
|
}
|
||||||
}
|
if (type > 29) return len*4; //RGBW
|
||||||
if (type > 31 && type < 48) return 5;
|
return len*3;
|
||||||
if (type == 44 || type == 45) return len*4; //RGBW
|
}
|
||||||
return len*3;
|
if (type > 31 && type < 48) return 5;
|
||||||
}
|
if (type == 44 || type == 45) return len*4; //RGBW
|
||||||
function UI(change=false)
|
return len*3;
|
||||||
{
|
}
|
||||||
var isRGBW = false, memu = 0;
|
function UI(change=false)
|
||||||
|
{
|
||||||
gId('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
|
var isRGBW = false, memu = 0;
|
||||||
|
|
||||||
if (d.Sf.LA.value == 255) laprev = 12;
|
gId('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
|
||||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
|
||||||
|
if (d.Sf.LA.value == 255) laprev = 12;
|
||||||
var s = d.getElementsByTagName("select");
|
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||||
for (i=0; i<s.length; i++) {
|
|
||||||
if (s[i].name.substring(0,2)=="LT") {
|
// enable/disable LED fields
|
||||||
n=s[i].name.substring(2);
|
var s = d.getElementsByTagName("select");
|
||||||
var type = parseInt(s[i].value,10);
|
for (i=0; i<s.length; i++) {
|
||||||
gId("p0d"+n).innerHTML = (type > 49) ? "Data:" : (type >41) ? "Pins:" : "Pin:";
|
// is the field a LED type?
|
||||||
gId("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
|
if (s[i].name.substring(0,2)=="LT") {
|
||||||
var LK = d.getElementsByName("L1"+n)[0];
|
n=s[i].name.substring(2);
|
||||||
|
var type = parseInt(s[i].value,10);
|
||||||
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value);
|
gId("p0d"+n).innerHTML = (type == 2 || type == 3) ? "IP address:" : (type > 49) ? "Data GPIO:" : (type >41) ? "GPIOs:" : "GPIO:";
|
||||||
|
gId("p1d"+n).innerHTML = (type > 49) ? "Clk GPIO:" : "";
|
||||||
for (p=1; p<5; p++) {
|
var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
||||||
var LK = d.getElementsByName("L"+p+n)[0];
|
|
||||||
if (!LK) continue;
|
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value); // calc memory
|
||||||
if ((type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
|
|
||||||
{
|
// enumerate pins
|
||||||
LK.style.display = "inline";
|
for (p=1; p<5; p++) {
|
||||||
LK.required = true;
|
var LK = d.getElementsByName("L"+p+n)[0]; // secondary pins
|
||||||
} else {
|
if (!LK) continue;
|
||||||
LK.style.display = "none";
|
if (((type == 2 || type == 3) && p<4) || (type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
|
||||||
LK.required = false;
|
{
|
||||||
LK.value="";
|
// display pin field
|
||||||
}
|
LK.style.display = "inline";
|
||||||
}
|
LK.required = true;
|
||||||
if (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)) isRGBW = true;
|
} else {
|
||||||
gId("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
|
// hide pin field
|
||||||
gId("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
|
LK.style.display = "none";
|
||||||
}
|
LK.required = false;
|
||||||
}
|
LK.value="";
|
||||||
|
}
|
||||||
var myC = d.querySelectorAll('.wc'),
|
}
|
||||||
l = myC.length;
|
if (change) {
|
||||||
for (i = 0; i < l; i++) {
|
// // blazoncek experimental extension
|
||||||
myC[i].style.display = (isRGBW) ? 'inline':'none';
|
// gId("ew"+n).checked = (type == 30 || type == 31 || type == 44 || type == 45); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||||
}
|
gId("ls"+n).value = n+1; // set LED start
|
||||||
|
if (type > 31 && type < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED
|
||||||
if (d.activeElement == d.getElementsByName("LC")[0]) {
|
}
|
||||||
var o = d.getElementsByClassName("iST");
|
// // blazoncek experimental extension
|
||||||
var i = o.length;
|
// gId("ew"+n).onclick = (type > 31 && type < 48) ? (function(){return false}) : (function(){}); // prevent change for analog
|
||||||
if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
|
// isRGBW |= gId("ew"+n).checked;
|
||||||
}
|
isRGBW |= (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||||
|
gId("co"+n).style.display = (type == 2 || type == 3 || type == 41 || type == 42) ? "none":"inline"; // hide color order for PWM W & WW/CW
|
||||||
var LCs = d.getElementsByTagName("input");
|
gId("dig"+n+"c").style.display = (type > 40 && type < 48) ? "none":"inline"; // hide count for analog
|
||||||
var sLC = 0, maxLC = 0;
|
gId("dig"+n+"r").style.display = (type == 2 || type == 3) ? "none":"inline"; // hide reversed for virtual
|
||||||
for (i=0; i<LCs.length; i++) {
|
gId("dig"+n+"s").style.display = (type == 2 || type == 3 || (type > 40 && type < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||||
var nm = LCs[i].name.substring(0,2);
|
gId("rev"+n).innerHTML = (type > 40 && type < 48) ? "Inverted":"Reverse (rotated 180°)"; // change reverse text for analog
|
||||||
if (nm=="LC" && LCs[i].name !== "LC") {
|
gId("psd"+n).innerHTML = (type > 40 && type < 48) ? "Index:":"Start:"; // change analog start description
|
||||||
var n=LCs[i].name.substring(2);
|
}
|
||||||
var c=parseInt(LCs[i].value,10);
|
}
|
||||||
if(gId("ls"+n).readOnly) gId("ls"+n).value=sLC;
|
// display white channel calculation method
|
||||||
if(c){sLC+=c;if(c>maxLC)maxLC=c;}
|
var myC = d.querySelectorAll('.wc'),
|
||||||
continue;
|
l = myC.length;
|
||||||
}
|
for (i = 0; i < l; i++) {
|
||||||
if (nm=="L0" || nm=="L1") {
|
myC[i].style.display = (isRGBW) ? 'inline':'none';
|
||||||
var lc=d.getElementsByName("LC"+LCs[i].name.substring(2))[0];
|
}
|
||||||
lc.max=maxPB;
|
// check for pin conflicts
|
||||||
}
|
var LCs = d.getElementsByTagName("input");
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
var sLC = 0, maxLC = 0;
|
||||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
for (i=0; i<LCs.length; i++) {
|
||||||
var p = [];
|
var nm = LCs[i].name.substring(0,2); // field name
|
||||||
if (d.um_p && Array.isArray(d.um_p)) for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]);
|
var n = LCs[i].name.substring(2); // bus number
|
||||||
for (j=0; j<LCs.length; j++) {
|
// do we have a led count field but not total led count
|
||||||
if (i==j) continue;
|
if (nm=="LC" && LCs[i].name !== "LC") {
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
var c=parseInt(LCs[i].value,10);
|
||||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
|
/*if(gId("ls"+n).readOnly)*/ gId("ls"+n).value=sLC; // update led start field
|
||||||
if (LCs[j].value!="" && LCs[j].value!="-1") p.push(parseInt(LCs[j].value,10));
|
if(c){sLC+=c;if(c>maxLC)maxLC=c;} // increase led count
|
||||||
}
|
continue;
|
||||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color="#fff";
|
}
|
||||||
}
|
// do we have led pins for digital leds
|
||||||
}
|
if (nm=="L0" || nm=="L1") {
|
||||||
|
var lc=d.getElementsByName("LC"+n)[0];
|
||||||
gId('m0').innerHTML = memu;
|
lc.max=maxPB; // update max led count value
|
||||||
bquot = memu / maxM * 100;
|
}
|
||||||
gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
|
// ignore IP address
|
||||||
gId('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none';
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
|
||||||
gId('ledwarning').style.color = (sLC > maxPB || maxLC > maxPB || bquot > 100) ? 'red':'orange';
|
var type = parseInt(d.getElementsByName("LT"+n)[0].value, 10); // LED type SELECT
|
||||||
gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>WARNING: Using over ${maxM}B!</b>)` : "") : "800 LEDs per pin";
|
if (type==2 || type==3) continue;
|
||||||
|
}
|
||||||
var val = Math.ceil((100 + sLC * laprev)/500)/2;
|
// check for pin conflicts
|
||||||
val = (val > 5) ? Math.ceil(val) : val;
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
||||||
var s = "";
|
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||||
var is12V = (d.Sf.LAsel.value == 30);
|
var p = []; // used pin array
|
||||||
var isWS2815 = (d.Sf.LAsel.value == 255);
|
if (d.um_p && Array.isArray(d.um_p)) for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with reservations
|
||||||
if (val < 1.02 && !is12V && !isWS2815)
|
for (j=0; j<LCs.length; j++) {
|
||||||
{
|
if (i==j) continue;
|
||||||
s = "ESP 5V pin with 1A USB supply";
|
var n2 = LCs[j].name.substring(0,2);
|
||||||
} else
|
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR") {
|
||||||
{
|
if (n2.substring(0,1)==="L") {
|
||||||
s += is12V ? "12V ": isWS2815 ? "WS2815 12V " : "5V ";
|
var m = LCs[j].name.substring(2);
|
||||||
s += val;
|
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||||
s += "A supply connected to LEDs";
|
if (t2==2 || t2==3) continue;
|
||||||
}
|
}
|
||||||
var val2 = Math.ceil((100 + sLC * laprev)/1500)/2;
|
if (LCs[j].value!="" && LCs[j].value!="-1") p.push(parseInt(LCs[j].value,10)); // add current pin
|
||||||
val2 = (val2 > 5) ? Math.ceil(val2) : val2;
|
}
|
||||||
var s2 = "(for most effects, ~";
|
}
|
||||||
s2 += val2;
|
// now check for conflicts
|
||||||
s2 += "A is enough)<br>";
|
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color=parseInt(LCs[i].value,10)>33?"orange":"#fff";
|
||||||
gId('psu').innerHTML = s;
|
}
|
||||||
gId('psu2').innerHTML = isWS2815 ? "" : s2;
|
}
|
||||||
gId("json").style.display = d.Sf.IT.value==8 ? "" : "none";
|
// update total led count
|
||||||
}
|
if (gId("LC").readOnly) d.getElementsByName("LC")[0].value = sLC;
|
||||||
function lastEnd(i) {
|
// if we are changing total led count update led count for 1st strip
|
||||||
if (i<1) return 0;
|
if (d.activeElement == d.getElementsByName("LC")[0]) {
|
||||||
v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value);
|
var o = d.getElementsByClassName("iST");
|
||||||
var type = parseInt(d.getElementsByName("LT"+(i-1))[0].value);
|
var i = o.length;
|
||||||
if (type > 31 && type < 48) v = 1; //PWM busses
|
if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
|
||||||
if (isNaN(v)) return 0;
|
}
|
||||||
return v;
|
// memory usage and warnings
|
||||||
}
|
gId('m0').innerHTML = memu;
|
||||||
function addLEDs(n)
|
bquot = memu / maxM * 100;
|
||||||
{
|
gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
|
||||||
if (n>1) {maxB=n; gId("+").style.display="inline"; return;}
|
gId('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none';
|
||||||
|
gId('ledwarning').style.color = (sLC > maxPB || maxLC > maxPB || bquot > 100) ? 'red':'orange';
|
||||||
var o = d.getElementsByClassName("iST");
|
gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>WARNING: Using over ${maxM}B!</b>)` : "") : "800 LEDs per GPIO";
|
||||||
var i = o.length;
|
// calculate power
|
||||||
|
var val = Math.ceil((100 + sLC * laprev)/500)/2;
|
||||||
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
|
val = (val > 5) ? Math.ceil(val) : val;
|
||||||
|
var s = "";
|
||||||
var f = gId("mLC");
|
var is12V = (d.Sf.LAsel.value == 30);
|
||||||
if (n==1) {
|
var isWS2815 = (d.Sf.LAsel.value == 255);
|
||||||
// npm run build has trouble minimizing spaces inside string
|
if (val < 1.02 && !is12V && !isWS2815)
|
||||||
var cn = `<div class="iST">
|
{
|
||||||
${i>0?'<hr style="width:260px">':''}
|
s = "ESP 5V pin with 1A USB supply";
|
||||||
${i+1}:
|
} else
|
||||||
<select name="LT${i}" onchange="UI()">
|
{
|
||||||
<option value="22">WS281x</option>
|
s += is12V ? "12V ": isWS2815 ? "WS2815 12V " : "5V ";
|
||||||
<option value="30">SK6812 RGBW</option>
|
s += val;
|
||||||
<option value="31">TM1814</option>
|
s += "A supply connected to LEDs";
|
||||||
<option value="24">400kHz</option>
|
}
|
||||||
<option value="50">WS2801</option>
|
var val2 = Math.ceil((100 + sLC * laprev)/1500)/2;
|
||||||
<option value="51">APA102</option>
|
val2 = (val2 > 5) ? Math.ceil(val2) : val2;
|
||||||
<option value="52">LPD8806</option>
|
var s2 = "(for most effects, ~";
|
||||||
<option value="53">P9813</option>
|
s2 += val2;
|
||||||
<option value="41">PWM White</option>
|
s2 += "A is enough)<br>";
|
||||||
<option value="42">PWM WWCW</option>
|
gId('psu').innerHTML = s;
|
||||||
<option value="43">PWM RGB</option>
|
gId('psu2').innerHTML = isWS2815 ? "" : s2;
|
||||||
<option value="44">PWM RGBW</option>
|
gId("json").style.display = d.Sf.IT.value==8 ? "" : "none";
|
||||||
<option value="45">PWM RGBWC</option>
|
}
|
||||||
</select>
|
function lastEnd(i) {
|
||||||
Color Order:
|
if (i<1) return 0;
|
||||||
<select name="CO${i}">
|
v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value);
|
||||||
<option value="0">GRB</option>
|
var type = parseInt(d.getElementsByName("LT"+(i-1))[0].value);
|
||||||
<option value="1">RGB</option>
|
if (type > 31 && type < 48) v = 1; //PWM busses
|
||||||
<option value="2">BRG</option>
|
if (isNaN(v)) return 0;
|
||||||
<option value="3">RBG</option>
|
return v;
|
||||||
<option value="4">BGR</option>
|
}
|
||||||
<option value="5">GBR</option>
|
function addLEDs(n)
|
||||||
</select><br>
|
{
|
||||||
<span id="p0d${i}">Pin:</span> <input type="number" class="xs" name="L0${i}" min="0" max="33" required onchange="UI()"/>
|
if (n>1) {maxB=n; gId("+").style.display="inline"; return;}
|
||||||
<span id="p1d${i}">Clock:</span> <input type="number" class="xs" name="L1${i}" min="0" max="33" onchange="UI()"/>
|
|
||||||
<span id="p2d${i}"></span><input type="number" class="xs" name="L2${i}" min="0" max="33" onchange="UI()"/>
|
var o = d.getElementsByClassName("iST");
|
||||||
<span id="p3d${i}"></span><input type="number" class="xs" name="L3${i}" min="0" max="33" onchange="UI()"/>
|
var i = o.length;
|
||||||
<span id="p4d${i}"></span><input type="number" class="xs" name="L4${i}" min="0" max="33" onchange="UI()"/>
|
|
||||||
<br>
|
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
|
||||||
<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">
|
var f = gId("mLC");
|
||||||
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
|
if (n==1) {
|
||||||
Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
// npm run build has trouble minimizing spaces inside string
|
||||||
Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"><br>
|
var cn = `<div class="iST">
|
||||||
</div>
|
<hr style="width:260px">
|
||||||
</div>`;
|
${i+1}:
|
||||||
f.insertAdjacentHTML("beforeend", cn);
|
<select name="LT${i}" onchange="UI(true)">
|
||||||
}
|
<option value="22" selected>WS281x</option>
|
||||||
if (n==-1) {
|
<option value="30">SK6812 RGBW</option>
|
||||||
o[--i].remove();--i;
|
<option value="31">TM1814</option>
|
||||||
}
|
<option value="24">400kHz</option>
|
||||||
|
<option value="50">WS2801</option>
|
||||||
gId("+").style.display = (i<maxB-1) ? "inline":"none";
|
<option value="51">APA102</option>
|
||||||
gId("-").style.display = (i>0) ? "inline":"none";
|
<option value="52">LPD8806</option>
|
||||||
|
<option value="53">P9813</option>
|
||||||
UI();
|
<option value="41">PWM White</option>
|
||||||
}
|
<option value="42">PWM WWCW</option>
|
||||||
function addBtn(i,p,t) {
|
<option value="43">PWM RGB</option>
|
||||||
var c = gId("btns").innerHTML;
|
<option value="44">PWM RGBW</option>
|
||||||
var bt = "BT" + i;
|
<option value="45">PWM RGBWC</option>
|
||||||
var be = "BE" + i;
|
<option value="2">Virtual RGB</option>
|
||||||
c += `Button ${i} pin: <input type="number" class="xs" min="-1" max="40" name="${bt}" onchange="UI()" value="${p}"> `;
|
<option value="3">Virtual RGBW</option>
|
||||||
c += `<select name="${be}">`
|
</select>
|
||||||
c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`;
|
<div id="co${i}" style="display:inline">Color Order:
|
||||||
c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`;
|
<select name="CO${i}">
|
||||||
c += `<option value="3" ${t==3?"selected":""}>Push inverted</option>`;
|
<option value="0">GRB</option>
|
||||||
c += `<option value="4" ${t==4?"selected":""}>Switch</option>`;
|
<option value="1">RGB</option>
|
||||||
c += `<option value="5" ${t==5?"selected":""}>PIR sensor</option>`;
|
<option value="2">BRG</option>
|
||||||
c += `<option value="6" ${t==6?"selected":""}>Touch</option>`;
|
<option value="3">RBG</option>
|
||||||
c += `<option value="7" ${t==7?"selected":""}>Analog</option>`;
|
<option value="4">BGR</option>
|
||||||
c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`;
|
<option value="5">GBR</option>
|
||||||
c += `</select>`;
|
</select></div>
|
||||||
c += `<span style="cursor: pointer;" onclick="off('${bt}')"> ×</span><br>`;
|
<br>
|
||||||
gId("btns").innerHTML = c;
|
<span id="p0d${i}">GPIO:</span><input type="number" name="L0${i}" min="0" max="33" required class="s" onchange="UI()"/>
|
||||||
}
|
<span id="p1d${i}"></span><input type="number" name="L1${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||||
function uploadFile(name) {
|
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||||
var req = new XMLHttpRequest();
|
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||||
req.addEventListener('load', function(){showToast(this.responseText)});
|
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||||
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
<br>
|
||||||
req.open("POST", "/upload");
|
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l" min="0" max="8191" value="${lastEnd(i)}" disabled readonly required />
|
||||||
var formData = new FormData();
|
<div id="dig${i}c" style="display:inline">Count: <input type="number" name="LC${i}" class="l" min="0" max="${maxPB}" value="1" required oninput="UI()" /></div>
|
||||||
formData.append("data", d.Sf.data.files[0], name);
|
<br>
|
||||||
req.send(formData);
|
<div id="dig${i}r" style="display:inline"><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div>
|
||||||
d.Sf.data.value = '';
|
<div id="dig${i}s" style="display:inline">Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"></div>
|
||||||
return false;
|
<br>
|
||||||
}
|
</div>`;
|
||||||
function GetV()
|
f.insertAdjacentHTML("beforeend", cn);
|
||||||
{
|
}
|
||||||
//values injected by server while sending HTML
|
if (n==-1) {
|
||||||
//maxM=5000;maxPB=1536;d.um_p=[1,6,7,8,9,10,11];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;addBtn(0,0,2);addBtn(1,3,4);addBtn(2,-1,0);d.Sf.IR.value=-1;
|
o[--i].remove();--i;
|
||||||
}
|
}
|
||||||
</script>
|
|
||||||
<style>
|
gId("+").style.display = (i<maxB-1) ? "inline":"none";
|
||||||
@import url("style.css");
|
gId("-").style.display = (i>0) ? "inline":"none";
|
||||||
</style>
|
|
||||||
</head>
|
UI();
|
||||||
<body onload="S()">
|
}
|
||||||
<form id="form_s" name="Sf" method="post">
|
function addBtn(i,p,t) {
|
||||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
var c = gId("btns").innerHTML;
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
var bt = "BT" + i;
|
||||||
<h2>LED & Hardware setup</h2>
|
var be = "BE" + i;
|
||||||
Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
|
c += `Button ${i} GPIO: <input type="number" min="-1" max="40" name="${bt}" onchange="UI()" class="s" value="${p}">`;
|
||||||
<i>Recommended power supply for brightest white:</i><br>
|
c += `<select name="${be}">`
|
||||||
<b><span id="psu">?</span></b><br>
|
c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`;
|
||||||
<span id="psu2"><br></span>
|
c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`;
|
||||||
<br>
|
c += `<option value="3" ${t==3?"selected":""}>Push inverted</option>`;
|
||||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
c += `<option value="4" ${t==4?"selected":""}>Switch</option>`;
|
||||||
<div id="abl">
|
c += `<option value="5" ${t==5?"selected":""}>PIR sensor</option>`;
|
||||||
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
c += `<option value="6" ${t==6?"selected":""}>Touch</option>`;
|
||||||
<div id="ampwarning" style="color: orange; display: none;">
|
c += `<option value="7" ${t==7?"selected":""}>Analog</option>`;
|
||||||
⚠ Your power supply provides high current.<br>
|
c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`;
|
||||||
To improve the safety of your setup,<br>
|
c += `</select>`;
|
||||||
please use thick cables,<br>
|
c += `<span style="cursor: pointer;" onclick="off('${bt}')"> ×</span><br>`;
|
||||||
multiple power injection points and a fuse!<br>
|
gId("btns").innerHTML = c;
|
||||||
</div>
|
}
|
||||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
function uploadFile(name) {
|
||||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
var req = new XMLHttpRequest();
|
||||||
If you are using an external power supply, enter its rating.<br>
|
req.addEventListener('load', function(){showToast(this.responseText)});
|
||||||
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
||||||
LED voltage (Max. current for a single LED):<br>
|
req.open("POST", "/upload");
|
||||||
<select name="LAsel" onchange="enLA()">
|
var formData = new FormData();
|
||||||
<option value="55" selected>5V default (55mA)</option>
|
formData.append("data", d.Sf.data.files[0], name);
|
||||||
<option value="35">5V efficient (35mA)</option>
|
req.send(formData);
|
||||||
<option value="30">12V (30mA)</option>
|
d.Sf.data.value = '';
|
||||||
<option value="255">WS2815 (12mA)</option>
|
return false;
|
||||||
<option value="50">Custom</option>
|
}
|
||||||
</select><br>
|
function GetV()
|
||||||
<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>
|
//values injected by server while sending HTML
|
||||||
</div>
|
//maxM=5000;maxPB=1536;d.um_p=[1,6,7,8,9,10,11];addLEDs(5);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;addBtn(0,0,2);addBtn(1,3,4);addBtn(2,-1,0);d.Sf.IR.value=-1;
|
||||||
<h3>Hardware setup</h3>
|
}
|
||||||
<div id="mLC">LED outputs:</div>
|
</script>
|
||||||
<button type="button" id="+" onclick="addLEDs(1)" style="display:none;border-radius:20px;height:36px;">+</button>
|
<style>@import url("style.css");</style>
|
||||||
<button type="button" id="-" onclick="addLEDs(-1)" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
|
</head>
|
||||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
<body onload="S()">
|
||||||
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
<form id="form_s" name="Sf" method="post">
|
||||||
<div id="ledwarning" style="color: orange; display: none;">
|
<div class="toprow">
|
||||||
⚠ You might run into stability or lag issues.<br>
|
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||||
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
|
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||||
</div>
|
</div>
|
||||||
Make a segment for each output: <input type="checkbox" name="MS"> <br>
|
<h2>LED & Hardware setup</h2>
|
||||||
<hr style="width:260px">
|
Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" disabled required readonly><br>
|
||||||
<div id="btns"></div>
|
<i>Recommended power supply for brightest white:</i><br>
|
||||||
Touch threshold: <input type="number" class="s" min="0" max="100" name="TT" required><br>
|
<b><span id="psu">?</span></b><br>
|
||||||
IR pin: <input type="number" class="xs" min="-1" max="40" name="IR" onchange="UI()"> <select name="IT" onchange="UI()">
|
<span id="psu2"><br></span>
|
||||||
<option value=0>Remote disabled</option>
|
<br>
|
||||||
<option value=1>24-key RGB</option>
|
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||||
<option value=2>24-key with CT</option>
|
<div id="abl">
|
||||||
<option value=3>40-key blue</option>
|
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||||
<option value=4>44-key RGB</option>
|
<div id="ampwarning" style="color: orange; display: none;">
|
||||||
<option value=5>21-key RGB</option>
|
⚠ Your power supply provides high current.<br>
|
||||||
<option value=6>6-key black</option>
|
To improve the safety of your setup,<br>
|
||||||
<option value=7>9-key red</option>
|
please use thick cables,<br>
|
||||||
<option value=8>JSON remote</option>
|
multiple power injection points and a fuse!<br>
|
||||||
</select><span style="cursor: pointer;" onclick="off('IR')"> ×</span><br>
|
</div>
|
||||||
<div id="json" style="display:none;">JSON file: <input type="file" name="data" accept=".json"> <input type="button" value="Upload" onclick="uploadFile('/ir.json');"><br></div>
|
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||||
<div id="toast"></div>
|
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||||
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a><br>
|
If you are using an external power supply, enter its rating.<br>
|
||||||
Relay pin: <input type="number" class="xs" min="-1" max="33" name="RL" onchange="UI()"> Invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')"> ×</span><br>
|
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
||||||
<hr style="width:260px">
|
LED voltage (Max. current for a single LED):<br>
|
||||||
<h3>Defaults</h3>
|
<select name="LAsel" onchange="enLA()">
|
||||||
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
|
<option value="55" selected>5V default (55mA)</option>
|
||||||
Default brightness: <input name="CA" type="number" class="s" min="0" max="255" required> (0-255)<br><br>
|
<option value="35">5V efficient (35mA)</option>
|
||||||
Apply preset <input name="BP" type="number" class="s" min="0" max="250" required> at boot (0 uses defaults)
|
<option value="30">12V (30mA)</option>
|
||||||
<br><br>
|
<option value="255">WS2815 (12mA)</option>
|
||||||
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
|
<option value="50">Custom</option>
|
||||||
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
|
</select><br>
|
||||||
Brightness factor: <input name="BF" type="number" class="s" min="1" max="255" required> %
|
<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>
|
||||||
<h3>Transitions</h3>
|
<i>Keep at default if you are unsure about your type of LEDs.</i><br>
|
||||||
Crossfade: <input type="checkbox" name="TF"><br>
|
</div>
|
||||||
Transition Time: <input name="TD" type="number" class="l" min="0" max="65500"> ms<br>
|
<h3>Hardware setup</h3>
|
||||||
Enable Palette transitions: <input type="checkbox" name="PF">
|
<div id="mLC">LED outputs:</div>
|
||||||
<h3>Timed light</h3>
|
<hr style="width:260px">
|
||||||
Default Duration: <input name="TL" type="number" class="s" min="1" max="255" required> min<br>
|
<button type="button" id="+" onclick="addLEDs(1)">+</button>
|
||||||
Default Target brightness: <input name="TB" type="number" class="s" min="0" max="255" required><br>
|
<button type="button" id="-" onclick="addLEDs(-1)">-</button><br>
|
||||||
Mode:
|
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||||
<select name="TW">
|
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||||
<option value="0">Wait and set</option>
|
<div id="ledwarning" style="color: orange; display: none;">
|
||||||
<option value="1">Fade</option>
|
⚠ You might run into stability or lag issues.<br>
|
||||||
<option value="2">Fade Color</option>
|
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
|
||||||
<option value="3">Sunrise</option>
|
</div>
|
||||||
</select>
|
<hr style="width:260px">
|
||||||
<h3>Advanced</h3>
|
Create a segment for each output: <input type="checkbox" name="MS"> <br>
|
||||||
Palette blending:
|
<hr style="width:260px">
|
||||||
<select name="PB">
|
<div id="btns"></div>
|
||||||
<option value="0">Linear (wrap if moving)</option>
|
Touch threshold: <input type="number" min="0" max="100" name="TT" required><br>
|
||||||
<option value="1">Linear (always wrap)</option>
|
IR GPIO: <input type="number" min="-1" max="40" name="IR" onchange="UI()" class="s"><select name="IT" onchange="UI()">
|
||||||
<option value="2">Linear (never wrap)</option>
|
<option value=0>Remote disabled</option>
|
||||||
<option value="3">None (not recommended)</option>
|
<option value=1>24-key RGB</option>
|
||||||
</select><br>
|
<option value=2>24-key with CT</option>
|
||||||
<span class="wc">
|
<option value=3>40-key blue</option>
|
||||||
Auto-calculate white channel from RGB:<br>
|
<option value=4>44-key RGB</option>
|
||||||
<select name="AW">
|
<option value=5>21-key RGB</option>
|
||||||
<option value=0>None</option>
|
<option value=6>6-key black</option>
|
||||||
<option value=1>Brighter</option>
|
<option value=7>9-key red</option>
|
||||||
<option value=2>Accurate</option>
|
<option value=8>JSON remote</option>
|
||||||
<option value=3>Dual</option>
|
</select><span style="cursor: pointer;" onclick="off('IR')"> ×</span><br>
|
||||||
<option value=4>Legacy</option>
|
<div id="json" style="display:none;">JSON file: <input type="file" name="data" accept=".json"> <input type="button" value="Upload" onclick="uploadFile('/ir.json');"><br></div>
|
||||||
</select>
|
<div id="toast"></div>
|
||||||
<br></span><hr>
|
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a><br>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
Relay GPIO: <input type="number" min="-1" max="33" name="RL" onchange="UI()" class="s"> invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')"> ×</span><br>
|
||||||
</form>
|
<hr style="width:260px">
|
||||||
</body>
|
<h3>Defaults</h3>
|
||||||
</html>
|
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
|
||||||
|
Default brightness: <input name="CA" type="number" class="m" min="0" max="255" required> (0-255)<br><br>
|
||||||
|
Apply preset <input name="BP" type="number" class="m" min="0" max="250" required> at boot (0 uses defaults)
|
||||||
|
<br><br>
|
||||||
|
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
|
||||||
|
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
|
||||||
|
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
||||||
|
<h3>Transitions</h3>
|
||||||
|
Crossfade: <input type="checkbox" name="TF"><br>
|
||||||
|
Transition Time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
|
||||||
|
Enable Palette transitions: <input type="checkbox" name="PF">
|
||||||
|
<h3>Timed light</h3>
|
||||||
|
Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
|
||||||
|
Default Target brightness: <input name="TB" type="number" class="m" min="0" max="255" required><br>
|
||||||
|
Mode:
|
||||||
|
<select name="TW">
|
||||||
|
<option value="0">Wait and set</option>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
@ -57,8 +57,10 @@
|
|||||||
</head>
|
</head>
|
||||||
<body onload="GetV()">
|
<body onload="GetV()">
|
||||||
<form id="form_s" name="Sf" method="post">
|
<form id="form_s" name="Sf" method="post">
|
||||||
|
<div class="toprow">
|
||||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
|
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
|
||||||
|
</div>
|
||||||
<h2>Security & Update setup</h2>
|
<h2>Security & Update setup</h2>
|
||||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||||
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
||||||
@ -70,17 +72,18 @@
|
|||||||
Factory reset: <input type="checkbox" name="RS"><br>
|
Factory reset: <input type="checkbox" name="RS"><br>
|
||||||
All settings and presets will be erased.<br><br>
|
All settings and presets will be erased.<br><br>
|
||||||
HTTP traffic is unencrypted. An attacker in the same network can intercept form data!
|
HTTP traffic is unencrypted. An attacker in the same network can intercept form data!
|
||||||
|
<hr>
|
||||||
<h3>Software Update</h3>
|
<h3>Software Update</h3>
|
||||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||||
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
||||||
<h3>Backup & Restore</h3>
|
<h3>Backup & Restore</h3>
|
||||||
<a class="btn lnk" href="/presets.json?download" target="download-frame">Backup presets</a><br>
|
<a class="btn lnk" href="/presets.json?download" target="download-frame">Backup presets</a><br>
|
||||||
<div>Restore presets<br><input type="file" name="data" accept=".json"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data,'/presets.json');"><br></div><br>
|
<div>Restore presets<br><input type="file" name="data" accept=".json"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data,'/presets.json');"><br></div><br>
|
||||||
<a class="btn lnk" href="/cfg.json?download" target="download-frame">Backup configuration</a><br>
|
<a class="btn lnk" href="/cfg.json?download" target="download-frame">Backup configuration</a><br>
|
||||||
<div>Restore configuration<br><input type="file" name="data2" accept=".json"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data2,'/cfg.json');"><br></div>
|
<div>Restore configuration<br><input type="file" name="data2" accept=".json"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data2,'/cfg.json');"><br></div>
|
||||||
<div style="color: #fa0;">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
<div style="color: #fa0;">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||||
Incorrect configuration may require a factory reset or re-flashing of your ESP.</div>
|
Incorrect configuration may require a factory reset or re-flashing of your ESP.</div>
|
||||||
For security reasons, passwords are not backed up.
|
For security reasons, passwords are not backed up.
|
||||||
<h3>About</h3>
|
<h3>About</h3>
|
||||||
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
|
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
|
||||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
|
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||||
|
@ -35,11 +35,14 @@ function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 556
|
|||||||
function S(){GetV();SetVal();}
|
function S(){GetV();SetVal();}
|
||||||
function GetV(){var d=document;}
|
function GetV(){var d=document;}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style></head>
|
<style>@import url("/style.css");</style>
|
||||||
|
</head>
|
||||||
<body onload="S()">
|
<body onload="S()">
|
||||||
<form id="form_s" name="Sf" method="post" onsubmit="GC()">
|
<form id="form_s" name="Sf" method="post" onsubmit="GC()">
|
||||||
|
<div class="toprow">
|
||||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||||
|
</div>
|
||||||
<h2>Sync setup</h2>
|
<h2>Sync setup</h2>
|
||||||
<h3>WLED Broadcast</h3>
|
<h3>WLED Broadcast</h3>
|
||||||
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
||||||
|
@ -46,13 +46,15 @@
|
|||||||
var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";
|
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++)
|
for (i=0;i<8;i++)
|
||||||
{
|
{
|
||||||
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" class=\"sml\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" class=\"sml\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" class=\"med\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||||
for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";
|
for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";
|
||||||
|
ih+="</tr>";
|
||||||
}
|
}
|
||||||
ih+="<tr><td><input name=\"W8\" id=\"W8\" type=\"number\" style=\"display:none\"><input id=\"W80\" type=\"checkbox\"></td><td>Sunrise<input name=\"H8\" value=\"255\" type=\"hidden\"></td><td><input name=\"N8\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T8\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
ih+="<tr><td><input name=\"W8\" id=\"W8\" type=\"number\" style=\"display:none\"><input id=\"W80\" type=\"checkbox\"></td><td>Sunrise<input name=\"H8\" class=\"sml\" value=\"255\" type=\"hidden\"></td><td><input name=\"N8\" class=\"sml\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T8\" class=\"med\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||||
for (j=1;j<8;j++) ih+="<td><input id=\"W8"+j+"\" type=\"checkbox\"></td>";
|
for (j=1;j<8;j++) ih+="<td><input id=\"W8"+j+"\" type=\"checkbox\"></td>";
|
||||||
ih+="<tr><td><input name=\"W9\" id=\"W9\" type=\"number\" style=\"display:none\"><input id=\"W90\" type=\"checkbox\"></td><td>Sunset<input name=\"H9\" value=\"255\" type=\"hidden\"></td><td><input name=\"N9\" type=\"number\" min=\"-59\" max=\"59\"><td><input name=\"T9\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
ih+="</tr><tr><td><input name=\"W9\" id=\"W9\" type=\"number\" style=\"display:none\"><input id=\"W90\" type=\"checkbox\"></td><td>Sunset<input name=\"H9\" class=\"sml\" value=\"255\" type=\"hidden\"></td><td><input name=\"N9\" class=\"sml\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T9\" class=\"med\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||||
for (j=1;j<8;j++) ih+="<td><input id=\"W9"+j+"\" type=\"checkbox\"></td>";
|
for (j=1;j<8;j++) ih+="<td><input id=\"W9"+j+"\" type=\"checkbox\"></td>";
|
||||||
|
ih+="</tr>";
|
||||||
gId("TMT").innerHTML=ih;
|
gId("TMT").innerHTML=ih;
|
||||||
}
|
}
|
||||||
function FC()
|
function FC()
|
||||||
@ -84,25 +86,25 @@
|
|||||||
td = tr.insertCell(0);
|
td = tr.insertCell(0);
|
||||||
td.innerHTML = `Button ${i}:`;
|
td.innerHTML = `Button ${i}:`;
|
||||||
td = tr.insertCell(1);
|
td = tr.insertCell(1);
|
||||||
td.innerHTML = `<input name="MP${i}" type="number" min="0" max="250" value="${p}" required>`;
|
td.innerHTML = `<input name="MP${i}" type="number" class="m" min="0" max="250" value="${p}" required>`;
|
||||||
td = tr.insertCell(2);
|
td = tr.insertCell(2);
|
||||||
td.innerHTML = `<input name="ML${i}" type="number" min="0" max="250" value="${l}" required>`;
|
td.innerHTML = `<input name="ML${i}" type="number" class="m" min="0" max="250" value="${l}" required>`;
|
||||||
td = tr.insertCell(3);
|
td = tr.insertCell(3);
|
||||||
td.innerHTML = `<input name="MD${i}" type="number" min="0" max="250" value="${d}" required>`;
|
td.innerHTML = `<input name="MD${i}" type="number" class="m" min="0" max="250" value="${d}" required>`;
|
||||||
}
|
}
|
||||||
function GetV()
|
function GetV()
|
||||||
{
|
{
|
||||||
//values injected by server while sending HTML
|
//values injected by server while sending HTML
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>@import url("/style.css");</style>
|
||||||
@import url("style.css");
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body onload="S()">
|
<body onload="S()">
|
||||||
<form id="form_s" name="Sf" method="post" onsubmit="Wd()">
|
<form id="form_s" name="Sf" method="post" onsubmit="Wd()">
|
||||||
|
<div class="toprow">
|
||||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||||
|
</div>
|
||||||
<h2>Time setup</h2>
|
<h2>Time setup</h2>
|
||||||
Get time from NTP server: <input type="checkbox" name="NT"><br>
|
Get time from NTP server: <input type="checkbox" name="NT"><br>
|
||||||
<input name="NS" maxlength="32"><br>
|
<input name="NS" maxlength="32"><br>
|
||||||
@ -131,8 +133,8 @@
|
|||||||
</select><br>
|
</select><br>
|
||||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||||
Current local time is <span class="times">unknown</span>.<br>
|
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">
|
Latitude (N): <input name="LT" type="number" class="xl" min="-66.6" max="66.6" step="0.01">
|
||||||
Longitude (E): <input name="LN" type="number" min="-180" max="180" step="0.01">
|
Longitude (E): <input name="LN" type="number" class="xl" min="-180" max="180" step="0.01">
|
||||||
<div id="sun" class="times"></div>
|
<div id="sun" class="times"></div>
|
||||||
<h3>Clock</h3>
|
<h3>Clock</h3>
|
||||||
Clock Overlay:
|
Clock Overlay:
|
||||||
@ -155,8 +157,8 @@
|
|||||||
</div>
|
</div>
|
||||||
Countdown Mode: <input type="checkbox" name="CE"><br>
|
Countdown Mode: <input type="checkbox" name="CE"><br>
|
||||||
Countdown Goal:<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>
|
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" 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>
|
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>
|
<h3>Macro presets</h3>
|
||||||
<b>Macros have moved!</b><br>
|
<b>Macros have moved!</b><br>
|
||||||
<i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br>
|
<i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<title>UI Settings</title>
|
<title>UI Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
var initial_ds, initial_st;
|
var initial_ds, initial_st, initial_su;
|
||||||
var sett = null;
|
var sett = null;
|
||||||
var l = {
|
var l = {
|
||||||
"comp":{
|
"comp":{
|
||||||
@ -21,8 +21,8 @@
|
|||||||
"pcmbot": "Show bottom tab bar in PC mode",
|
"pcmbot": "Show bottom tab bar in PC mode",
|
||||||
"pid": "Show preset IDs",
|
"pid": "Show preset IDs",
|
||||||
"seglen": "Set segment length instead of stop LED",
|
"seglen": "Set segment length instead of stop LED",
|
||||||
"css": "Enable custom CSS",
|
"css": "Enable custom CSS",
|
||||||
"hdays": "Enable custom Holidays list"
|
"hdays": "Enable custom Holidays list"
|
||||||
},
|
},
|
||||||
"theme":{
|
"theme":{
|
||||||
"alpha": {
|
"alpha": {
|
||||||
@ -147,10 +147,18 @@
|
|||||||
gId('lserr').innerHTML = "⚠ Settings JSON saving failed. (" + e + ")";
|
gId('lserr').innerHTML = "⚠ Settings JSON saving failed. (" + e + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cLS()
|
||||||
|
{
|
||||||
|
localStorage.removeItem('wledP');
|
||||||
|
localStorage.removeItem('wledPmt');
|
||||||
|
localStorage.removeItem('wledPalx');
|
||||||
|
showToast("Cleared.");
|
||||||
|
}
|
||||||
|
|
||||||
function Save() {
|
function Save() {
|
||||||
SetLS();
|
SetLS();
|
||||||
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st) d.Sf.submit();
|
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st || d.Sf.SU.checked != initial_su) d.Sf.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function S()
|
function S()
|
||||||
@ -158,6 +166,7 @@
|
|||||||
GetV();
|
GetV();
|
||||||
initial_ds = d.Sf.DS.value;
|
initial_ds = d.Sf.DS.value;
|
||||||
initial_st = d.Sf.ST.checked;
|
initial_st = d.Sf.ST.checked;
|
||||||
|
initial_su = d.Sf.SU.checked;
|
||||||
GetLS();
|
GetLS();
|
||||||
}
|
}
|
||||||
function H()
|
function H()
|
||||||
@ -208,7 +217,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body onload="S()">
|
<body onload="S()">
|
||||||
<form id="form_s" name="Sf" method="post">
|
<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>
|
<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>
|
<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>
|
<span id="lssuc" style="color:green; display:none">✔ Local UI settings saved!</span>
|
||||||
@ -217,6 +226,7 @@
|
|||||||
<h2>Web Setup</h2>
|
<h2>Web Setup</h2>
|
||||||
Server description: <input name="DS" maxlength="32"><br>
|
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>
|
||||||
|
Enable simplified UI: <input type="checkbox" name="SU"><br>
|
||||||
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
|
<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>
|
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>
|
Refresh the main UI to apply changes.</i><br>
|
||||||
@ -236,11 +246,12 @@
|
|||||||
<span class="l">BG image URL</span>: <input id="theme_bg_url" class="agi" oninput="checkRandomBg()"><br>
|
<span class="l">BG image URL</span>: <input id="theme_bg_url" class="agi" oninput="checkRandomBg()"><br>
|
||||||
<span class="l">Random BG image</span>: <input type="checkbox" id="theme_bg_random" class="agi cb" onchange="setRandomBg()"><br>
|
<span class="l">Random BG image</span>: <input type="checkbox" id="theme_bg_random" class="agi cb" onchange="setRandomBg()"><br>
|
||||||
<input id="theme_base" class="agi" style="display:none">
|
<input id="theme_base" class="agi" style="display:none">
|
||||||
<span class="l"></span>: <input type="checkbox" id="comp_css" class="agi cb"><br>
|
<span class="l"></span>: <input type="checkbox" id="comp_css" class="agi cb"><br>
|
||||||
<div id="skin">Custom CSS: <input type="file" name="data" accept=".css"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data,'/skin.css');"><br></div>
|
<div id="skin">Custom CSS: <input type="file" name="data" accept=".css"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data,'/skin.css');"><br></div>
|
||||||
<span class="l"></span>: <input type="checkbox" id="comp_hdays" class="agi cb"><br>
|
<span class="l"></span>: <input type="checkbox" id="comp_hdays" class="agi cb"><br>
|
||||||
<div id="holidays">Holidays: <input type="file" name="data2" accept=".json"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data2,'/holidays.json');"><br></div>
|
<div id="holidays">Holidays: <input type="file" name="data2" accept=".json"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data2,'/holidays.json');"><br></div>
|
||||||
<div id="toast"></div>
|
<div id="toast"></div>
|
||||||
|
<hr><button type="button" onclick="cLS()">Clear local storage</button>
|
||||||
<hr><button type="button" onclick="B()">Back</button><button type="button" onclick="Save()">Save</button>
|
<hr><button type="button" onclick="B()">Back</button><button type="button" onclick="Save()">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
@ -81,10 +81,10 @@
|
|||||||
case "number":
|
case "number":
|
||||||
c = `value="${o}"`;
|
c = `value="${o}"`;
|
||||||
if (f.substr(-3)==="pin") {
|
if (f.substr(-3)==="pin") {
|
||||||
c += ' max="39" min="-1" style="width:40px;"';
|
c += ' max="39" min="-1" class="s"';
|
||||||
t = "int";
|
t = "int";
|
||||||
} else {
|
} else {
|
||||||
c += ' step="any" style="width:100px;"';
|
c += ' step="any" class="xxl"';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -133,9 +133,7 @@
|
|||||||
}
|
}
|
||||||
function GetV() {}
|
function GetV() {}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>@import url("/style.css");</style>
|
||||||
@import url("style.css");
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="S()">
|
<body onload="S()">
|
||||||
|
@ -18,14 +18,14 @@
|
|||||||
//values injected by server while sending HTML
|
//values injected by server while sending HTML
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>@import url("/style.css");</style>
|
||||||
@import url("style.css");
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body onload="GetV()">
|
<body onload="GetV()">
|
||||||
<form id="form_s" name="Sf" method="post">
|
<form id="form_s" name="Sf" method="post">
|
||||||
|
<div class="toprow">
|
||||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
|
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
|
||||||
|
</div>
|
||||||
<h2>WiFi setup</h2>
|
<h2>WiFi setup</h2>
|
||||||
<h3>Connect to existing network</h3>
|
<h3>Connect to existing network</h3>
|
||||||
Network name (SSID, empty to not connect): <br><input name="CS" maxlength="32"><br>
|
Network name (SSID, empty to not connect): <br><input name="CS" maxlength="32"><br>
|
||||||
@ -53,28 +53,29 @@
|
|||||||
Hide AP name: <input type="checkbox" name="AH"><br>
|
Hide AP name: <input type="checkbox" name="AH"><br>
|
||||||
AP password (leave empty for open):<br> <input type="password" name="AP" maxlength="63" pattern="(.{8,63})|()" title="Empty or min. 8 characters"><br>
|
AP password (leave empty for open):<br> <input type="password" name="AP" maxlength="63" pattern="(.{8,63})|()" title="Empty or min. 8 characters"><br>
|
||||||
Access Point WiFi channel: <input name="AC" type="number" class="xs" min="1" max="13" required><br>
|
Access Point WiFi channel: <input name="AC" type="number" class="xs" min="1" max="13" required><br>
|
||||||
AP opens:
|
AP opens:
|
||||||
<select name="AB">
|
<select name="AB">
|
||||||
<option value="0">No connection after boot</option>
|
<option value="0">No connection after boot</option>
|
||||||
<option value="1">Disconnected</option>
|
<option value="1">Disconnected</option>
|
||||||
<option value="2">Always</option>
|
<option value="2">Always</option>
|
||||||
<option value="3">Never (not recommended)</option></select><br>
|
<option value="3">Never (not recommended)</option></select><br>
|
||||||
AP IP: <span class="sip"> Not active </span><br>
|
AP IP: <span class="sip"> Not active </span><br>
|
||||||
<h3>Experimental</h3>
|
<h3>Experimental</h3>
|
||||||
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
||||||
<i>Can help with connectivity issues.<br>
|
<i>Can help with connectivity issues.<br>
|
||||||
Do not enable if WiFi is working correctly, increases power consumption.</i>
|
Do not enable if WiFi is working correctly, increases power consumption.</i>
|
||||||
<div id="ethd">
|
<div id="ethd">
|
||||||
<h3>Ethernet Type</h3>
|
<h3>Ethernet Type</h3>
|
||||||
<select name="ETH">
|
<select name="ETH">
|
||||||
<option value="0">None</option>
|
<option value="0">None</option>
|
||||||
<option value="2">ESP32-POE</option>
|
<option value="2">ESP32-POE</option>
|
||||||
<option value="6">ESP32Deux</option>
|
<option value="6">ESP32Deux</option>
|
||||||
<option value="4">QuinLED-ESP32</option>
|
<option value="4">QuinLED-ESP32</option>
|
||||||
<option value="5">TwilightLord-ESP32</option>
|
<option value="5">TwilightLord-ESP32</option>
|
||||||
<option value="3">WESP32</option>
|
<option value="3">WESP32</option>
|
||||||
<option value="1">WT32-ETH01</option>
|
<option value="1">WT32-ETH01</option>
|
||||||
</select><br><br></div>
|
</select><br><br>
|
||||||
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
|
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
|
||||||
</form>
|
</form>
|
||||||
|
858
wled00/data/simple.css
Normal file
858
wled00/data/simple.css
Normal file
File diff suppressed because one or more lines are too long
172
wled00/data/simple.htm
Normal file
172
wled00/data/simple.htm
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="theme-color" content="#222222">
|
||||||
|
<meta content="yes" name="apple-mobile-web-app-capable">
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAGACGAAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAE1JREFUOI1j/P//PwOxgNGeAUMxE9G6cQCKDWAhpADZ2f8PMjBS3QW08QK20KaZC2gfC9hCnqouoNgARgY7zMxAyNlUdQHlXiAlO2MDAD63EVqNHAe0AAAAAElFTkSuQmCC"/>
|
||||||
|
<title>WLED</title>
|
||||||
|
<script>function feedback(){}</script>
|
||||||
|
<link rel="stylesheet" href="simple.css">
|
||||||
|
</head>
|
||||||
|
<body onload="onLoad()">
|
||||||
|
|
||||||
|
<div id="cv" class="overlay">Loading WLED UI...</div>
|
||||||
|
<noscript><div class="overlay" style="opacity:1;">Sorry, WLED UI needs JavaScript!</div></noscript>
|
||||||
|
<div id="bg"></div>
|
||||||
|
|
||||||
|
<div class="wrapper" id="top">
|
||||||
|
<div class="tab top">
|
||||||
|
<div class="btnwrap">
|
||||||
|
<button id="buttonPower" onclick="togglePower()"><i class="icons"></i><p class="tab-label">Power</p></button>
|
||||||
|
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
||||||
|
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button></div>
|
||||||
|
<button onclick="window.location.href='/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||||
|
<button id="buttonCP" onclick="tglCP()"><i class="icons"></i><p class="tab-label">Expand</p></button>
|
||||||
|
<button id="buttonBri" onclick="tglBri()"><i class="icons"></i><p class="tab-label">Brightness</p></button>
|
||||||
|
</div>
|
||||||
|
<div id="briwrap">
|
||||||
|
<p class="label hd">Global brightness</p>
|
||||||
|
<div class="il">
|
||||||
|
<i class="icons slider-icon" onclick="tglTheme()"></i>
|
||||||
|
<div class="sliderwrap il">
|
||||||
|
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
||||||
|
<div class="sliderdisplay"></div>
|
||||||
|
</div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class ="container">
|
||||||
|
<div class="tabcontent">
|
||||||
|
<div id="picker" class="center"></div>
|
||||||
|
|
||||||
|
<div id="qcs-w" class="center">
|
||||||
|
<div class="qcs" onclick="pC('#ff0000');" title="Red" style="background-color:#ff0000;"></div>
|
||||||
|
<div class="qcs" onclick="pC('#ffa000');" title="Orange" style="background-color:#ffa000;"></div>
|
||||||
|
<div class="qcs" onclick="pC('#ffc800');" title="Yellow" style="background-color:#ffc800;"></div>
|
||||||
|
<div class="qcs" onclick="pC('#ffe0a0');" title="Warm White" style="background-color:#ffe0a0;"></div>
|
||||||
|
<div class="qcs" onclick="pC('#ffffff');" title="White" style="background-color:#ffffff;"></div>
|
||||||
|
<div class="qcs qcsb" onclick="pC('#000000');" title="Black" style="background-color:#000000;"></div><br>
|
||||||
|
<div class="qcs" onclick="pC('#ff00ff');" title="Pink" style="background-color:#ff00ff;"></div>
|
||||||
|
<div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
|
||||||
|
<div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
|
||||||
|
<div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
|
||||||
|
<div class="qcs" onclick="pC('rnd');" title="Random" style="background:linear-gradient(to right, red, orange, yellow, green, blue, purple);transform: translateY(-11px);">R</div>
|
||||||
|
</div>
|
||||||
|
<div id="csl" class="center" style="display: none;">
|
||||||
|
<button class="xxs btn" onclick="selectSlot(0);">1</button>
|
||||||
|
<button class="xxs btn" onclick="selectSlot(1);">2</button>
|
||||||
|
<button class="xxs btn" onclick="selectSlot(2);">3</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="wwrap" class="center">
|
||||||
|
<p class="label h">White channel</p>
|
||||||
|
<i class="icons slider-icon" id="wht" title="White channel"></i>
|
||||||
|
<div class="sliderwrap il">
|
||||||
|
<input id="sliderW" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||||
|
<div class="sliderdisplay"></div>
|
||||||
|
</div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="Segments" class="center">
|
||||||
|
<div id="segcont"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="QuickLoad" class="center">
|
||||||
|
<p class="label h">Quick Load</p>
|
||||||
|
<div id="pql"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="Presets" class="center" style="display:none;">
|
||||||
|
<p class="label h">Presets</p>
|
||||||
|
<div class="fnd">
|
||||||
|
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pcont')" onfocus="search(this)" />
|
||||||
|
<span onclick="clean(this)" class="icons"></span>
|
||||||
|
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||||
|
</div>
|
||||||
|
<div id="pcont" class="list"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="Effects" class="center">
|
||||||
|
<p class="label h">Effect</p>
|
||||||
|
<!--p class="label h">Effect speed</p-->
|
||||||
|
<div title="Effect speed">
|
||||||
|
<i class="icons slider-icon"></i>
|
||||||
|
<div class="sliderwrap il">
|
||||||
|
<input id="sliderSpeed" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||||
|
<div class="sliderdisplay"></div>
|
||||||
|
</div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
|
</div>
|
||||||
|
<!--p class="label h">Effect intensity</p-->
|
||||||
|
<div title="Effect intensity">
|
||||||
|
<i class="icons slider-icon" onclick="tglLabels()"></i>
|
||||||
|
<div class="sliderwrap il">
|
||||||
|
<input id="sliderIntensity" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||||
|
<div class="sliderdisplay"></div>
|
||||||
|
</div>
|
||||||
|
<output class="sliderbubble"></output>
|
||||||
|
</div>
|
||||||
|
<div style="padding-bottom:20px;">
|
||||||
|
<div onclick="tglFxDropdown()" class="c btn" id="fxBtn"><i class="icons"></i> Solid</div>
|
||||||
|
<div onclick="tglPalDropdown()" class="c btn" id="palBtn"><i class="icons"></i>Default</div>
|
||||||
|
<div id="fxDropdown" class="dd-content">
|
||||||
|
<div class="fnd">
|
||||||
|
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this)" />
|
||||||
|
<span onclick="clean(this)" class="icons"></span>
|
||||||
|
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||||
|
</div>
|
||||||
|
<div id="fxlist" class="list">
|
||||||
|
<div class="lstI" data-id="0" onClick="setX(0)"><a href="#0" onClick="setX(0)">Solid</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="palDropdown" class="dd-content">
|
||||||
|
<div class="fnd">
|
||||||
|
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pallist')" onfocus="search(this)" />
|
||||||
|
<span onclick="clean(this)" class="icons"></span>
|
||||||
|
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||||
|
</div>
|
||||||
|
<div id="pallist" class="list">
|
||||||
|
<div class="lstI" data-id="0" onClick="setPalette(0)"><a href="#0" onClick="setPalette(0)">Default</a><div class="lstIprev"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="connind"></div>
|
||||||
|
<div id="toast"></div>
|
||||||
|
<div id="namelabel" onclick="toggleNodes()"></div>
|
||||||
|
|
||||||
|
<div id="info" class="modal">
|
||||||
|
<div id="imgw">
|
||||||
|
<img class="wi" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAFCAYAAAC5Fuf5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABbSURBVChTlY9bDoAwDMNW7n9nwCipytQN4Z8tbrTHmDmF4oPzyldwRqp1SSdnV/NuZuzqerAByxXznBw3igkeFEfXyUuhK/yFM0CxJfyqXZEOc6/Sr9/bf7uIC5Nwd7orMvAPAAAAAElFTkSuQmCC" />
|
||||||
|
</div><br>
|
||||||
|
<div id="kv">Loading...</div><br>
|
||||||
|
<button class="btn infobtn" onclick="loadInfo()">Refresh</button>
|
||||||
|
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
||||||
|
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||||
|
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
|
||||||
|
<span class="h">Made with <span id="heart">❤︎</span> by Aircoookie and the WLED community</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="nodes" class="modal">
|
||||||
|
<div id="ndlt">WLED instances</div>
|
||||||
|
<div id="kn">Loading...</div><br>
|
||||||
|
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
|
||||||
|
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<i id="roverstar" class="icons huge" onclick="setLor(0)"></i><br>
|
||||||
|
<script src="iro.js"></script>
|
||||||
|
<script src="rangetouch.js"></script>
|
||||||
|
<script src="simple.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
1398
wled00/data/simple.js
Normal file
1398
wled00/data/simple.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,13 +14,21 @@ button, .btn {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-family: Verdana, sans-serif;
|
font-family: Verdana, sans-serif;
|
||||||
border: 0.3ch solid #333;
|
border: 0.3ch solid #333;
|
||||||
|
border-radius: 24px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
margin: 12px 8px 8px;
|
margin: 12px 8px 8px;
|
||||||
padding: 1px 6px;
|
padding: 8px 12px;
|
||||||
|
min-width: 48px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.toprow {
|
||||||
|
top: 0;
|
||||||
|
position: sticky;
|
||||||
|
background-color:#222;
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
.lnk {
|
.lnk {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
@ -35,8 +43,12 @@ input {
|
|||||||
font-family: Verdana, sans-serif;
|
font-family: Verdana, sans-serif;
|
||||||
border: 0.5ch solid #333;
|
border: 0.5ch solid #333;
|
||||||
}
|
}
|
||||||
|
input[type="text"] {
|
||||||
|
font-size: medium;
|
||||||
|
}
|
||||||
input[type="number"] {
|
input[type="number"] {
|
||||||
width: 4em;
|
width: 4em;
|
||||||
|
font-size: medium;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
}
|
}
|
||||||
input[type="number"].xxl {
|
input[type="number"].xxl {
|
||||||
@ -57,8 +69,12 @@ input[type="number"].s {
|
|||||||
input[type="number"].xs {
|
input[type="number"].xs {
|
||||||
width: 42px;
|
width: 42px;
|
||||||
}
|
}
|
||||||
|
select {
|
||||||
|
margin: 2px;
|
||||||
|
font-size: medium;
|
||||||
|
}
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
transform: scale(1.5);
|
transform: scale(2);
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
@ -15,9 +15,11 @@ void handleAlexa();
|
|||||||
void onAlexaChange(EspalexaDevice* dev);
|
void onAlexaChange(EspalexaDevice* dev);
|
||||||
|
|
||||||
//blynk.cpp
|
//blynk.cpp
|
||||||
|
#ifndef WLED_DISABLE_BLYNK
|
||||||
void initBlynk(const char* auth, const char* host, uint16_t port);
|
void initBlynk(const char* auth, const char* host, uint16_t port);
|
||||||
void handleBlynk();
|
void handleBlynk();
|
||||||
void updateBlynk();
|
void updateBlynk();
|
||||||
|
#endif
|
||||||
|
|
||||||
//button.cpp
|
//button.cpp
|
||||||
void shortPressAction(uint8_t b=0);
|
void shortPressAction(uint8_t b=0);
|
||||||
@ -94,7 +96,7 @@ void sendHuePoll();
|
|||||||
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
||||||
|
|
||||||
//ir.cpp
|
//ir.cpp
|
||||||
bool decodeIRCustom(uint32_t code);
|
//bool decodeIRCustom(uint32_t code);
|
||||||
void applyRepeatActions();
|
void applyRepeatActions();
|
||||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
||||||
void changeEffectSpeed(int8_t amount);
|
void changeEffectSpeed(int8_t amount);
|
||||||
@ -195,6 +197,7 @@ bool updateVal(const String* req, const char* key, byte* val, byte minv=0, byte
|
|||||||
|
|
||||||
//udp.cpp
|
//udp.cpp
|
||||||
void notify(byte callMode, bool followUp=false);
|
void notify(byte callMode, bool followUp=false);
|
||||||
|
void realtimeBoroadcast(IPAddress client, uint16_t length, byte *buffer, bool isRGBW);
|
||||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||||
void handleNotifications();
|
void handleNotifications();
|
||||||
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
|
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
|
||||||
@ -224,14 +227,11 @@ class UsermodManager {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
void connected();
|
void connected();
|
||||||
|
|
||||||
void addToJsonState(JsonObject& obj);
|
void addToJsonState(JsonObject& obj);
|
||||||
void addToJsonInfo(JsonObject& obj);
|
void addToJsonInfo(JsonObject& obj);
|
||||||
void readFromJsonState(JsonObject& obj);
|
void readFromJsonState(JsonObject& obj);
|
||||||
|
|
||||||
void addToConfig(JsonObject& obj);
|
void addToConfig(JsonObject& obj);
|
||||||
bool readFromConfig(JsonObject& obj);
|
bool readFromConfig(JsonObject& obj);
|
||||||
void onMqttConnect(bool sessionPresent);
|
void onMqttConnect(bool sessionPresent);
|
||||||
|
@ -380,10 +380,10 @@ String getContentType(AsyncWebServerRequest* request, String filename){
|
|||||||
else if(filename.endsWith(".htm")) return "text/html";
|
else if(filename.endsWith(".htm")) return "text/html";
|
||||||
else if(filename.endsWith(".html")) 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(".js")) return "application/javascript";
|
||||||
else if(filename.endsWith(".json")) return "application/json";
|
else if(filename.endsWith(".json")) return "application/json";
|
||||||
else if(filename.endsWith(".png")) return "image/png";
|
else if(filename.endsWith(".png")) return "image/png";
|
||||||
// else if(filename.endsWith(".gif")) return "image/gif";
|
else if(filename.endsWith(".gif")) return "image/gif";
|
||||||
else if(filename.endsWith(".jpg")) return "image/jpeg";
|
else if(filename.endsWith(".jpg")) return "image/jpeg";
|
||||||
else if(filename.endsWith(".ico")) return "image/x-icon";
|
else if(filename.endsWith(".ico")) return "image/x-icon";
|
||||||
// else if(filename.endsWith(".xml")) return "text/xml";
|
// else if(filename.endsWith(".xml")) return "text/xml";
|
||||||
|
@ -42,7 +42,7 @@ function B(){window.history.back()}function U(){document.getElementById("uf").st
|
|||||||
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}#msg{display:none}
|
.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"
|
</style></head><body><h2>WLED Software Update</h2><form method="POST"
|
||||||
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
||||||
Installed version: 0.13.0-b2<br>Download the latest binary: <a
|
Installed version: 0.13.0-bl3<br>Download the latest binary: <a
|
||||||
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
|
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
|
||||||
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
|
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
|
||||||
</a><br><input type="file" class="bt" name="update" required><br><input
|
</a><br><input type="file" class="bt" name="update" required><br><input
|
||||||
|
File diff suppressed because one or more lines are too long
1819
wled00/html_simple.h
Normal file
1819
wled00/html_simple.h
Normal file
File diff suppressed because it is too large
Load Diff
4371
wled00/html_ui.h
4371
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -101,7 +101,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
|||||||
hueError = HUE_ERROR_JSON_PARSING; return;
|
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
|
if (hueErrorCode)//hue bridge returned error
|
||||||
{
|
{
|
||||||
hueError = hueErrorCode;
|
hueError = hueErrorCode;
|
||||||
|
@ -79,6 +79,9 @@ void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is no longer needed due to JSON IR mod
|
||||||
|
*
|
||||||
//Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control
|
//Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control
|
||||||
//IR codes themselves can be defined directly after "case" or in "ir_codes.h"
|
//IR codes themselves can be defined directly after "case" or in "ir_codes.h"
|
||||||
bool decodeIRCustom(uint32_t code)
|
bool decodeIRCustom(uint32_t code)
|
||||||
@ -94,6 +97,7 @@ bool decodeIRCustom(uint32_t code)
|
|||||||
if (code != IRCUSTOM_MACRO1) colorUpdated(CALL_MODE_BUTTON); //don't update color again if we apply macro, it already does it
|
if (code != IRCUSTOM_MACRO1) colorUpdated(CALL_MODE_BUTTON); //don't update color again if we apply macro, it already does it
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||||
{
|
{
|
||||||
@ -162,9 +166,10 @@ void decodeIR(uint32_t code)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastValidCode = 0; irTimesRepeated = 0;
|
lastValidCode = 0; irTimesRepeated = 0;
|
||||||
if (decodeIRCustom(code)) return;
|
//if (decodeIRCustom(code)) return;
|
||||||
if (irEnabled == 8) { // any remote configurable with ir.json file
|
if (irEnabled == 8) { // any remote configurable with ir.json file
|
||||||
decodeIRJson(code);
|
decodeIRJson(code);
|
||||||
|
colorUpdated(CALL_MODE_BUTTON);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (code > 0xFFFFFF) return; //invalid code
|
if (code > 0xFFFFFF) return; //invalid code
|
||||||
@ -566,14 +571,17 @@ Sample:
|
|||||||
void decodeIRJson(uint32_t code)
|
void decodeIRJson(uint32_t code)
|
||||||
{
|
{
|
||||||
char objKey[10];
|
char objKey[10];
|
||||||
const char* cmd;
|
|
||||||
String cmdStr;
|
String cmdStr;
|
||||||
DynamicJsonDocument irDoc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument irDoc(JSON_BUFFER_SIZE);
|
||||||
JsonObject fdo;
|
JsonObject fdo;
|
||||||
JsonObject jsonCmdObj;
|
JsonObject jsonCmdObj;
|
||||||
|
|
||||||
sprintf(objKey, "\"0x%X\":", code);
|
sprintf_P(objKey, PSTR("\"0x%lX\":"), (unsigned long)code);
|
||||||
|
|
||||||
|
// attempt to read command from ir.json
|
||||||
|
// this may fail for two reasons: ir.json does not exist or IR code not found
|
||||||
|
// if the IR code is not found readObjectFromFile() will clean() irDoc JSON document
|
||||||
|
// so we can differentiate between the two
|
||||||
readObjectFromFile("/ir.json", objKey, &irDoc);
|
readObjectFromFile("/ir.json", objKey, &irDoc);
|
||||||
fdo = irDoc.as<JsonObject>();
|
fdo = irDoc.as<JsonObject>();
|
||||||
lastValidCode = 0;
|
lastValidCode = 0;
|
||||||
@ -583,8 +591,7 @@ void decodeIRJson(uint32_t code)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = fdo["cmd"]; //string
|
cmdStr = fdo["cmd"].as<String>();;
|
||||||
cmdStr = String(cmd);
|
|
||||||
jsonCmdObj = fdo["cmd"]; //object
|
jsonCmdObj = fdo["cmd"]; //object
|
||||||
|
|
||||||
if (!cmdStr.isEmpty())
|
if (!cmdStr.isEmpty())
|
||||||
@ -617,8 +624,8 @@ void decodeIRJson(uint32_t code)
|
|||||||
if (!cmdStr.startsWith("win&")) {
|
if (!cmdStr.startsWith("win&")) {
|
||||||
cmdStr = "win&" + cmdStr;
|
cmdStr = "win&" + cmdStr;
|
||||||
}
|
}
|
||||||
handleSet(nullptr, cmdStr, false);
|
handleSet(nullptr, cmdStr, false);
|
||||||
}
|
}
|
||||||
} else if (!jsonCmdObj.isNull()) {
|
} else if (!jsonCmdObj.isNull()) {
|
||||||
// command is JSON object
|
// command is JSON object
|
||||||
//allow applyPreset() to reuse JSON buffer, or it would alloc. a second buffer and run out of mem.
|
//allow applyPreset() to reuse JSON buffer, or it would alloc. a second buffer and run out of mem.
|
||||||
@ -653,9 +660,7 @@ void handleIR()
|
|||||||
{
|
{
|
||||||
if (results.value != 0) // only print results if anything is received ( != 0 )
|
if (results.value != 0) // only print results if anything is received ( != 0 )
|
||||||
{
|
{
|
||||||
Serial.print("IR recv\r\n0x");
|
DEBUG_PRINTF("IR recv: 0x%lX\n", (unsigned long)results.value);
|
||||||
Serial.println((uint32_t)results.value, HEX);
|
|
||||||
Serial.println();
|
|
||||||
}
|
}
|
||||||
decodeIR(results.value);
|
decodeIR(results.value);
|
||||||
irrecv->resume();
|
irrecv->resume();
|
||||||
|
222
wled00/json.cpp
222
wled00/json.cpp
@ -17,11 +17,36 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
|
|
||||||
uint16_t start = elem[F("start")] | seg.start;
|
uint16_t start = elem[F("start")] | seg.start;
|
||||||
int stop = elem["stop"] | -1;
|
int stop = elem["stop"] | -1;
|
||||||
|
|
||||||
if (stop < 0) {
|
if (stop < 0) {
|
||||||
uint16_t len = elem[F("len")];
|
uint16_t len = elem[F("len")];
|
||||||
stop = (len > 0) ? start + len : seg.stop;
|
stop = (len > 0) ? start + len : seg.stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem["n"]) {
|
||||||
|
// name field exists
|
||||||
|
if (seg.name) { //clear old name
|
||||||
|
delete[] seg.name;
|
||||||
|
seg.name = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * name = elem["n"].as<const char*>();
|
||||||
|
size_t len = 0;
|
||||||
|
if (name != nullptr) len = strlen(name);
|
||||||
|
if (len > 0 && len < 33) {
|
||||||
|
seg.name = new char[len+1];
|
||||||
|
if (seg.name) strlcpy(seg.name, name, 33);
|
||||||
|
} else {
|
||||||
|
// but is empty (already deleted above)
|
||||||
|
elem.remove("n");
|
||||||
|
}
|
||||||
|
} else if (start != seg.start || stop != seg.stop) {
|
||||||
|
// clearing or setting segment without name field
|
||||||
|
if (seg.name) {
|
||||||
|
delete[] seg.name;
|
||||||
|
seg.name = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t grp = elem["grp"] | seg.grouping;
|
uint16_t grp = elem["grp"] | seg.grouping;
|
||||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||||
strip.setSegment(id, start, stop, grp, spc);
|
strip.setSegment(id, start, stop, grp, spc);
|
||||||
@ -54,38 +79,48 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
{
|
{
|
||||||
int rgbw[] = {0,0,0,0};
|
int rgbw[] = {0,0,0,0};
|
||||||
bool colValid = false;
|
bool colValid = false;
|
||||||
JsonArray colX = colarr[i];
|
if (colarr[i].is<unsigned long>()) {
|
||||||
if (colX.isNull()) {
|
// unsigned long RGBW (@blazoncek v2 experimental API implementation)
|
||||||
byte brgbw[] = {0,0,0,0};
|
uint32_t colX = colarr[i];
|
||||||
const char* hexCol = colarr[i];
|
rgbw[0] = (colX >> 16) & 0xFF;
|
||||||
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
|
rgbw[1] = (colX >> 8) & 0xFF;
|
||||||
int kelvin = colarr[i] | -1;
|
rgbw[2] = (colX ) & 0xFF;
|
||||||
if (kelvin < 0) continue;
|
rgbw[3] = (colX >> 24) & 0xFF;
|
||||||
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;
|
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
|
||||||
|
|
||||||
if (!colValid) continue;
|
byte cp = copyArray(colX, rgbw, 4);
|
||||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
if (cp == 1 && rgbw[0] == 0)
|
||||||
{
|
seg.setColor(i, 0, id);
|
||||||
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
colValid = true;
|
||||||
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
}
|
||||||
} else { //normal case, apply directly to segment
|
|
||||||
seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
|
if (!colValid) continue;
|
||||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||||
|
{
|
||||||
|
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
||||||
|
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
||||||
|
} else { //normal case, apply directly to segment
|
||||||
|
seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
|
||||||
|
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,16 +171,16 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
strip.fill(0);
|
strip.fill(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t start = 0, stop = 0;
|
//uint16_t start = 0, stop = 0;
|
||||||
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
||||||
|
|
||||||
for (uint16_t i = 0; i < iarr.size(); i++) {
|
for (uint16_t i = 0; i < iarr.size(); i++) {
|
||||||
if(iarr[i].is<JsonInteger>()) {
|
if(iarr[i].is<JsonInteger>()) {
|
||||||
if (!set) {
|
if (!set) {
|
||||||
start = iarr[i];
|
//start = iarr[i];
|
||||||
set = 1;
|
set = 1;
|
||||||
} else {
|
} else {
|
||||||
stop = iarr[i];
|
//stop = iarr[i];
|
||||||
set = 2;
|
set = 2;
|
||||||
}
|
}
|
||||||
} else { //color
|
} else { //color
|
||||||
@ -161,13 +196,6 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
for (uint8_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
for (uint8_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set < 2) stop = start + 1;
|
|
||||||
for (uint16_t i = start; i < stop; i++) {
|
|
||||||
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
|
||||||
}
|
|
||||||
if (!set) start++;
|
|
||||||
set = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strip.setPixelSegment(255);
|
strip.setPixelSegment(255);
|
||||||
@ -180,6 +208,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
|
|
||||||
bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||||
{
|
{
|
||||||
|
DEBUG_PRINTLN(F("Deserializing state"));
|
||||||
|
|
||||||
strip.applyToAllSelected = false;
|
strip.applyToAllSelected = false;
|
||||||
bool stateResponse = root[F("v")] | false;
|
bool stateResponse = root[F("v")] | false;
|
||||||
|
|
||||||
@ -200,14 +230,6 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
transitionDelayTemp = transitionDelay;
|
transitionDelayTemp = transitionDelay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr = root[F("tt")] | -1;
|
|
||||||
if (tr >= 0)
|
|
||||||
{
|
|
||||||
transitionDelayTemp = tr;
|
|
||||||
transitionDelayTemp *= 100;
|
|
||||||
jsonTransitionOnce = true;
|
|
||||||
}
|
|
||||||
strip.setTransition(transitionDelayTemp);
|
strip.setTransition(transitionDelayTemp);
|
||||||
|
|
||||||
tr = root[F("tb")] | -1;
|
tr = root[F("tb")] | -1;
|
||||||
@ -287,16 +309,24 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
|
|
||||||
usermods.readFromJsonState(root);
|
usermods.readFromJsonState(root);
|
||||||
|
|
||||||
|
int8_t ledmap = root[F("ledmap")] | -1;
|
||||||
|
if (ledmap >= 0) {
|
||||||
|
strip.deserializeMap(ledmap);
|
||||||
|
}
|
||||||
|
|
||||||
int ps = root[F("psave")] | -1;
|
int ps = root[F("psave")] | -1;
|
||||||
if (ps > 0) {
|
if (ps > 0) {
|
||||||
|
DEBUG_PRINTLN(F("Saving preset"));
|
||||||
savePreset(ps, true, nullptr, root);
|
savePreset(ps, true, nullptr, root);
|
||||||
} else {
|
} else {
|
||||||
ps = root[F("pdel")] | -1; //deletion
|
ps = root[F("pdel")] | -1; //deletion
|
||||||
if (ps > 0) {
|
if (ps > 0) {
|
||||||
|
DEBUG_PRINTLN(F("Deleting preset"));
|
||||||
deletePreset(ps);
|
deletePreset(ps);
|
||||||
}
|
}
|
||||||
ps = root["ps"] | -1; //load preset (clears state request!)
|
ps = root["ps"] | -1; //load preset (clears state request!)
|
||||||
if (ps >= 0) {
|
if (ps >= 0) {
|
||||||
|
DEBUG_PRINTLN(F("Applying preset"));
|
||||||
if (!presetId) unloadPlaylist(); //stop playlist if preset changed manually
|
if (!presetId) unloadPlaylist(); //stop playlist if preset changed manually
|
||||||
applyPreset(ps, callMode);
|
applyPreset(ps, callMode);
|
||||||
return stateResponse;
|
return stateResponse;
|
||||||
@ -339,12 +369,15 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
|||||||
byte segbri = seg.opacity;
|
byte segbri = seg.opacity;
|
||||||
root["bri"] = (segbri) ? segbri : 255;
|
root["bri"] = (segbri) ? segbri : 255;
|
||||||
|
|
||||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 3; i++)
|
// to conserve RAM we will serialize the col array manually
|
||||||
{
|
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
|
||||||
|
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||||
|
const char *format = strip.isRgbw ? PSTR("[%u,%u,%u,%u]") : PSTR("[%u,%u,%u]");
|
||||||
|
for (uint8_t i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
byte segcol[4]; byte* c = segcol;
|
byte segcol[4]; byte* c = segcol;
|
||||||
|
|
||||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||||
{
|
{
|
||||||
c = (i == 0)? col:colSec;
|
c = (i == 0)? col:colSec;
|
||||||
@ -352,14 +385,11 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
|||||||
segcol[0] = (byte)(seg.colors[i] >> 16); segcol[1] = (byte)(seg.colors[i] >> 8);
|
segcol[0] = (byte)(seg.colors[i] >> 16); segcol[1] = (byte)(seg.colors[i] >> 8);
|
||||||
segcol[2] = (byte)(seg.colors[i]); segcol[3] = (byte)(seg.colors[i] >> 24);
|
segcol[2] = (byte)(seg.colors[i]); segcol[3] = (byte)(seg.colors[i] >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
char tmpcol[22];
|
char tmpcol[22];
|
||||||
if (strip.isRgbw) sprintf_P(tmpcol, PSTR("[%u,%u,%u,%u]"), c[0], c[1], c[2], c[3]);
|
sprintf_P(tmpcol, format, (unsigned)c[0], (unsigned)c[1], (unsigned)c[2], (unsigned)c[3]);
|
||||||
else sprintf_P(tmpcol, PSTR("[%u,%u,%u]"), c[0], c[1], c[2]);
|
strcat(colstr, i<2 ? strcat_P(tmpcol, PSTR(",")) : tmpcol);
|
||||||
|
}
|
||||||
strcat(colstr, i<2 ? strcat(tmpcol,",") : tmpcol);
|
strcat_P(colstr, PSTR("]"));
|
||||||
}
|
|
||||||
strcat(colstr,"]");
|
|
||||||
root["col"] = serialized(colstr);
|
root["col"] = serialized(colstr);
|
||||||
|
|
||||||
root["fx"] = seg.mode;
|
root["fx"] = seg.mode;
|
||||||
@ -377,10 +407,11 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
|||||||
root["on"] = (bri > 0);
|
root["on"] = (bri > 0);
|
||||||
root["bri"] = briLast;
|
root["bri"] = briLast;
|
||||||
root[F("transition")] = transitionDelay/100; //in 100ms
|
root[F("transition")] = transitionDelay/100; //in 100ms
|
||||||
|
root[F("tdd")] = transitionDelayDefault/100; //in 100ms
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forPreset) {
|
if (!forPreset) {
|
||||||
if (errorFlag) root[F("error")] = errorFlag;
|
if (errorFlag) {root[F("error")] = errorFlag; errorFlag = ERR_NONE;}
|
||||||
|
|
||||||
root[F("ps")] = currentPreset;
|
root[F("ps")] = currentPreset;
|
||||||
root[F("pl")] = currentPlaylist;
|
root[F("pl")] = currentPlaylist;
|
||||||
@ -411,6 +442,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
|||||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||||
{
|
{
|
||||||
WS2812FX::Segment sg = strip.getSegment(s);
|
WS2812FX::Segment sg = strip.getSegment(s);
|
||||||
|
// TODO: add logic to stop at 16 segments if using versionAPI==1 on ESP8266
|
||||||
if (sg.isActive())
|
if (sg.isActive())
|
||||||
{
|
{
|
||||||
JsonObject seg0 = seg.createNestedObject();
|
JsonObject seg0 = seg.createNestedObject();
|
||||||
@ -452,6 +484,15 @@ void serializeInfo(JsonObject root)
|
|||||||
leds[F("count")] = ledCount;
|
leds[F("count")] = ledCount;
|
||||||
leds[F("rgbw")] = strip.isRgbw;
|
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?
|
leds[F("wv")] = strip.isRgbw && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed?
|
||||||
|
|
||||||
|
JsonArray leds_pin = leds.createNestedArray("pin");
|
||||||
|
for (uint8_t s=0; s<busses.getNumBusses(); s++) {
|
||||||
|
Bus *bus = busses.getBus(s);
|
||||||
|
uint8_t pins[5];
|
||||||
|
bus->getPins(pins);
|
||||||
|
leds_pin.add(pins[0]); // need to elaborate this for multipin strips
|
||||||
|
}
|
||||||
|
|
||||||
leds[F("pwr")] = strip.currentMilliamps;
|
leds[F("pwr")] = strip.currentMilliamps;
|
||||||
leds[F("fps")] = strip.getFps();
|
leds[F("fps")] = strip.getFps();
|
||||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||||
@ -530,9 +571,11 @@ void serializeInfo(JsonObject root)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
root[F("freeheap")] = ESP.getFreeHeap();
|
root[F("freeheap")] = ESP.getFreeHeap();
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||||
|
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||||
|
#endif
|
||||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||||
|
|
||||||
|
|
||||||
usermods.addToJsonInfo(root);
|
usermods.addToJsonInfo(root);
|
||||||
|
|
||||||
byte os = 0;
|
byte os = 0;
|
||||||
@ -655,37 +698,37 @@ void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
|||||||
curPalette.add("r");
|
curPalette.add("r");
|
||||||
break;
|
break;
|
||||||
case 2: //primary color only
|
case 2: //primary color only
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
break;
|
break;
|
||||||
case 3: //primary + secondary
|
case 3: //primary + secondary
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
break;
|
break;
|
||||||
case 4: //primary + secondary + tertiary
|
case 4: //primary + secondary + tertiary
|
||||||
curPalette.add(F("c3"));
|
curPalette.add("c3");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
break;
|
break;
|
||||||
case 5: {//primary + secondary (+tert if not off), more distinct
|
case 5: {//primary + secondary (+tert if not off), more distinct
|
||||||
|
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
curPalette.add(F("c2"));
|
curPalette.add("c2");
|
||||||
curPalette.add(F("c3"));
|
curPalette.add("c3");
|
||||||
curPalette.add(F("c3"));
|
curPalette.add("c3");
|
||||||
curPalette.add(F("c3"));
|
curPalette.add("c3");
|
||||||
curPalette.add(F("c3"));
|
curPalette.add("c3");
|
||||||
curPalette.add(F("c3"));
|
curPalette.add("c3");
|
||||||
curPalette.add(F("c1"));
|
curPalette.add("c1");
|
||||||
break;}
|
break;}
|
||||||
case 6: //Party colors
|
case 6: //Party colors
|
||||||
setPaletteColors(curPalette, PartyColors_p);
|
setPaletteColors(curPalette, PartyColors_p);
|
||||||
@ -793,8 +836,7 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("JSON buffer size: ");
|
DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", doc.memoryUsage(), subJson);
|
||||||
DEBUG_PRINTLN(doc.memoryUsage());
|
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -804,13 +846,13 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||||
{
|
{
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
AsyncWebSocketClient * wsc = nullptr;
|
AsyncWebSocketClient * wsc = nullptr;
|
||||||
if (!request) { //not HTTP, use Websockets
|
if (!request) { //not HTTP, use Websockets
|
||||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
|
||||||
wsc = ws.client(wsClient);
|
wsc = ws.client(wsClient);
|
||||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint16_t used = ledCount;
|
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
|
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||||
|
@ -190,8 +190,10 @@ void updateInterfaces(uint8_t callMode)
|
|||||||
espalexaDevice->setColor(col[0], col[1], col[2]);
|
espalexaDevice->setColor(col[0], col[1], col[2]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef WLED_DISABLE_BLYNK
|
||||||
if (callMode != CALL_MODE_BLYNK &&
|
if (callMode != CALL_MODE_BLYNK &&
|
||||||
callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
|
callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
|
||||||
|
#endif
|
||||||
doPublishMqtt = true;
|
doPublishMqtt = true;
|
||||||
lastInterfaceUpdate = millis();
|
lastInterfaceUpdate = millis();
|
||||||
}
|
}
|
||||||
@ -285,7 +287,9 @@ void handleNightlight()
|
|||||||
setLedsStandard();
|
setLedsStandard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifndef WLED_DISABLE_BLYNK
|
||||||
updateBlynk();
|
updateBlynk();
|
||||||
|
#endif
|
||||||
if (macroNl > 0)
|
if (macroNl > 0)
|
||||||
applyPreset(macroNl);
|
applyPreset(macroNl);
|
||||||
nightlightActiveOld = false;
|
nightlightActiveOld = false;
|
||||||
|
@ -124,22 +124,22 @@ void publishMqtt()
|
|||||||
sprintf_P(s, PSTR("%u"), bri);
|
sprintf_P(s, PSTR("%u"), bri);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/g"));
|
strcat_P(subuf, PSTR("/g"));
|
||||||
mqtt->publish(subuf, 0, true, s);
|
mqtt->publish(subuf, 0, true, s); // retain message
|
||||||
|
|
||||||
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/c"));
|
strcat_P(subuf, PSTR("/c"));
|
||||||
mqtt->publish(subuf, 0, true, s);
|
mqtt->publish(subuf, 0, true, s); // retain message
|
||||||
|
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/status"));
|
strcat_P(subuf, PSTR("/status"));
|
||||||
mqtt->publish(subuf, 0, true, "online");
|
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
|
||||||
|
|
||||||
char apires[1024];
|
char apires[1024]; // allocating 1024 bytes from stack can be risky
|
||||||
XML_response(nullptr, apires);
|
XML_response(nullptr, apires);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/v"));
|
strcat_P(subuf, PSTR("/v"));
|
||||||
mqtt->publish(subuf, 0, false, apires);
|
mqtt->publish(subuf, 0, false, apires); // do not retain message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ bool initMqtt()
|
|||||||
|
|
||||||
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
||||||
strcat_P(mqttStatusTopic, PSTR("/status"));
|
strcat_P(mqttStatusTopic, PSTR("/status"));
|
||||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline");
|
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
||||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||||
mqtt->connect();
|
mqtt->connect();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,6 +1,17 @@
|
|||||||
#include "src/dependencies/timezone/Timezone.h"
|
#include "src/dependencies/timezone/Timezone.h"
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include "wled_math.h"
|
#ifndef WLED_USE_REAL_MATH
|
||||||
|
#include "wled_math.h"
|
||||||
|
#else
|
||||||
|
#define sin_t sin
|
||||||
|
#define cos_t cos
|
||||||
|
#define tan_t tan
|
||||||
|
#define asin_t asin
|
||||||
|
#define acos_t acos
|
||||||
|
#define atan_t atan
|
||||||
|
#define fmod_t fmod
|
||||||
|
#define floor_t floor
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquires time from NTP server
|
* Acquires time from NTP server
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "pin_manager.h"
|
#include "pin_manager.h"
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
static void DebugPrintOwnerTag(PinOwner tag)
|
static void DebugPrintOwnerTag(PinOwner tag)
|
||||||
{
|
{
|
||||||
uint32_t q = static_cast<uint8_t>(tag);
|
uint32_t q = static_cast<uint8_t>(tag);
|
||||||
@ -10,6 +11,7 @@ static void DebugPrintOwnerTag(PinOwner tag)
|
|||||||
DEBUG_PRINT(F("(no owner)"));
|
DEBUG_PRINT(F("(no owner)"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Actual allocation/deallocation routines
|
/// Actual allocation/deallocation routines
|
||||||
bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
||||||
@ -19,12 +21,14 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
|||||||
|
|
||||||
// if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided
|
// if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided
|
||||||
if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
|
if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN DEALLOC: IO "));
|
DEBUG_PRINT(F("PIN DEALLOC: IO "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINT(F(" allocated by "));
|
DEBUG_PRINT(F(" allocated by "));
|
||||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||||
DEBUG_PRINT(F(", but attempted de-allocation by "));
|
DEBUG_PRINT(F(", but attempted de-allocation by "));
|
||||||
DebugPrintOwnerTag(tag);
|
DebugPrintOwnerTag(tag);
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,6 +38,7 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
|||||||
ownerTag[gpio] = PinOwner::None;
|
ownerTag[gpio] = PinOwner::None;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
|
bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
|
||||||
{
|
{
|
||||||
bool shouldFail = false;
|
bool shouldFail = false;
|
||||||
@ -46,17 +51,21 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isPinOk(gpio, mptArray[i].isOutput)) {
|
if (!isPinOk(gpio, mptArray[i].isOutput)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN ALLOC: Invalid pin attempted to be allocated: "));
|
DEBUG_PRINT(F("PIN ALLOC: Invalid pin attempted to be allocated: "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
|
#endif
|
||||||
shouldFail = true;
|
shouldFail = true;
|
||||||
}
|
}
|
||||||
if (isPinAllocated(gpio)) {
|
if (isPinAllocated(gpio)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
|
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINT(F(" already allocated by "));
|
DEBUG_PRINT(F(" already allocated by "));
|
||||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
|
#endif
|
||||||
shouldFail = true;
|
shouldFail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,15 +88,18 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag)
|
bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag)
|
||||||
{
|
{
|
||||||
if (!isPinOk(gpio, output)) return false;
|
if (!isPinOk(gpio, output)) return false;
|
||||||
if (isPinAllocated(gpio)) {
|
if (isPinAllocated(gpio)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN ALLOC: Pin "));
|
DEBUG_PRINT(F("PIN ALLOC: Pin "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINT(F(" already allocated by "));
|
DEBUG_PRINT(F(" already allocated by "));
|
||||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +118,7 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag)
|
|||||||
if (!isPinOk(gpio, false)) return true;
|
if (!isPinOk(gpio, false)) return true;
|
||||||
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
|
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
|
||||||
byte by = gpio >> 3;
|
byte by = gpio >> 3;
|
||||||
byte bi = gpio - 8*by;
|
byte bi = gpio - (by<<3);
|
||||||
return bitRead(pinAlloc[by], bi);
|
return bitRead(pinAlloc[by], bi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
#include "const.h" // for USERMOD_* values
|
#include "const.h" // for USERMOD_* values
|
||||||
|
|
||||||
typedef struct PinManagerPinType {
|
typedef struct PinManagerPinType {
|
||||||
int8_t pin;
|
int8_t pin;
|
||||||
uint8_t isOutput;
|
bool isOutput;
|
||||||
} managed_pin_type;
|
} managed_pin_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -23,7 +23,6 @@ typedef struct PinManagerPinType {
|
|||||||
enum struct PinOwner : uint8_t {
|
enum struct PinOwner : uint8_t {
|
||||||
None = 0, // default == legacy == unspecified owner
|
None = 0, // default == legacy == unspecified owner
|
||||||
// High bit is set for all built-in pin owners
|
// High bit is set for all built-in pin owners
|
||||||
// StatusLED -- THIS SHOULD NEVER BE ALLOCATED -- see handleStatusLED()
|
|
||||||
Ethernet = 0x81,
|
Ethernet = 0x81,
|
||||||
BusDigital = 0x82,
|
BusDigital = 0x82,
|
||||||
BusDigital2 = 0x83,
|
BusDigital2 = 0x83,
|
||||||
@ -88,7 +87,9 @@ class PinManagerClass {
|
|||||||
#endif
|
#endif
|
||||||
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
||||||
|
|
||||||
|
// will return true for reserved pins
|
||||||
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
||||||
|
// will return false for reserved pins
|
||||||
bool isPinOk(byte gpio, bool output = true);
|
bool isPinOk(byte gpio, bool output = true);
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
@ -90,7 +90,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strip.isRgbw = false;
|
|
||||||
uint8_t colorOrder, type, skip;
|
uint8_t colorOrder, type, skip;
|
||||||
uint16_t length, start;
|
uint16_t length, start;
|
||||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||||
@ -105,6 +104,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
|
char 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 cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
|
||||||
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
|
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
|
||||||
|
//char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||||
if (!request->hasArg(lp)) {
|
if (!request->hasArg(lp)) {
|
||||||
DEBUG_PRINTLN(F("No data.")); break;
|
DEBUG_PRINTLN(F("No data.")); break;
|
||||||
}
|
}
|
||||||
@ -114,25 +114,24 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
|
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
|
||||||
}
|
}
|
||||||
type = request->arg(lt).toInt();
|
type = request->arg(lt).toInt();
|
||||||
strip.isRgbw = strip.isRgbw || BusManager::isRgbw(type);
|
//if (request->hasArg(ew)) SET_BIT(type,7); else UNSET_BIT(type,7); // hack bit 7 to indicate RGBW (as a LED type override if necessary)
|
||||||
skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0;
|
skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0;
|
||||||
|
|
||||||
|
colorOrder = request->arg(co).toInt();
|
||||||
|
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
|
||||||
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
|
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
|
||||||
length = request->arg(lc).toInt();
|
t += length = request->arg(lc).toInt();
|
||||||
} else {
|
} else {
|
||||||
break; // no parameter
|
break; // no parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
colorOrder = request->arg(co).toInt();
|
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : 0;
|
|
||||||
|
|
||||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skip);
|
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skip);
|
||||||
doInitBusses = true;
|
doInitBusses = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
t = request->arg(F("LC")).toInt();
|
ledCount = request->arg(F("LC")).toInt();
|
||||||
if (t > 0 && t <= MAX_LEDS) ledCount = t;
|
|
||||||
|
|
||||||
// upate other pins
|
// upate other pins
|
||||||
int hw_ir_pin = request->arg(F("IR")).toInt();
|
int hw_ir_pin = request->arg(F("IR")).toInt();
|
||||||
@ -181,7 +180,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
|
|
||||||
fadeTransition = request->hasArg(F("TF"));
|
fadeTransition = request->hasArg(F("TF"));
|
||||||
t = request->arg(F("TD")).toInt();
|
t = request->arg(F("TD")).toInt();
|
||||||
if (t > 0) transitionDelay = t;
|
if (t >= 0) transitionDelay = t;
|
||||||
transitionDelayDefault = t;
|
transitionDelayDefault = t;
|
||||||
strip.paletteFade = request->hasArg(F("PF"));
|
strip.paletteFade = request->hasArg(F("PF"));
|
||||||
|
|
||||||
@ -202,6 +201,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
{
|
{
|
||||||
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
|
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
|
||||||
syncToggleReceive = request->hasArg(F("ST"));
|
syncToggleReceive = request->hasArg(F("ST"));
|
||||||
|
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||||
|
if (simplifiedUI ^ request->hasArg(F("SU"))) {
|
||||||
|
// UI selection changed, invalidate browser cache
|
||||||
|
cacheInvalidate++;
|
||||||
|
}
|
||||||
|
simplifiedUI = request->hasArg(F("SU"));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//SYNC
|
//SYNC
|
||||||
@ -595,9 +601,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t startI = mainseg.start;
|
uint16_t startI = mainseg.start;
|
||||||
uint16_t stopI = mainseg.stop;
|
uint16_t stopI = mainseg.stop;
|
||||||
uint8_t grpI = mainseg.grouping;
|
uint8_t grpI = mainseg.grouping;
|
||||||
uint16_t spcI = mainseg.spacing;
|
uint16_t spcI = mainseg.spacing;
|
||||||
pos = req.indexOf(F("&S=")); //segment start
|
pos = req.indexOf(F("&S=")); //segment start
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
startI = getNumVal(&req, pos);
|
startI = getNumVal(&req, pos);
|
||||||
@ -617,6 +623,30 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
}
|
}
|
||||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
|
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
|
||||||
|
|
||||||
|
pos = req.indexOf(F("RV=")); //Segment reverse
|
||||||
|
if (pos > 0) mainseg.setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
||||||
|
|
||||||
|
pos = req.indexOf(F("MI=")); //Segment mirror
|
||||||
|
if (pos > 0) mainseg.setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
|
||||||
|
|
||||||
|
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
|
||||||
|
if (pos > 0) {
|
||||||
|
byte segbri = getNumVal(&req, pos);
|
||||||
|
mainseg.setOption(SEG_OPTION_ON, segbri, selectedSeg);
|
||||||
|
if (segbri) {
|
||||||
|
mainseg.setOpacity(segbri, selectedSeg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = req.indexOf(F("SW=")); //segment power
|
||||||
|
if (pos > 0) {
|
||||||
|
switch (getNumVal(&req, pos)) {
|
||||||
|
case 0: mainseg.setOption(SEG_OPTION_ON, false); break;
|
||||||
|
case 1: mainseg.setOption(SEG_OPTION_ON, true); break;
|
||||||
|
default: mainseg.setOption(SEG_OPTION_ON, !mainseg.getOption(SEG_OPTION_ON)); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pos = req.indexOf(F("PS=")); //saves current in preset
|
pos = req.indexOf(F("PS=")); //saves current in preset
|
||||||
if (pos > 0) savePreset(getNumVal(&req, pos));
|
if (pos > 0) savePreset(getNumVal(&req, pos));
|
||||||
|
|
||||||
@ -707,7 +737,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
strip.applyToAllSelected = true;
|
strip.applyToAllSelected = true;
|
||||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
||||||
} else {
|
} else {
|
||||||
strip.getSegment(selectedSeg).setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg);
|
mainseg.setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,24 +841,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
pos = req.indexOf(F("TT="));
|
pos = req.indexOf(F("TT="));
|
||||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||||
|
|
||||||
//Segment reverse
|
|
||||||
pos = req.indexOf(F("RV="));
|
|
||||||
if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
|
||||||
|
|
||||||
//Segment reverse
|
|
||||||
pos = req.indexOf(F("MI="));
|
|
||||||
if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
|
|
||||||
|
|
||||||
//Segment brightness/opacity
|
|
||||||
pos = req.indexOf(F("SB="));
|
|
||||||
if (pos > 0) {
|
|
||||||
byte segbri = getNumVal(&req, pos);
|
|
||||||
strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri, selectedSeg);
|
|
||||||
if (segbri) {
|
|
||||||
strip.getSegment(selectedSeg).setOpacity(segbri, selectedSeg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//set time (unix timestamp)
|
//set time (unix timestamp)
|
||||||
pos = req.indexOf(F("ST="));
|
pos = req.indexOf(F("ST="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
|
@ -91,6 +91,12 @@ void notify(byte callMode, bool followUp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void realtimeBoroadcast(IPAddress client, uint16_t length, byte *buffer, bool isRGBW)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void realtimeLock(uint32_t timeoutMs, byte md)
|
void realtimeLock(uint32_t timeoutMs, byte md)
|
||||||
{
|
{
|
||||||
if (!realtimeMode && !realtimeOverride){
|
if (!realtimeMode && !realtimeOverride){
|
||||||
@ -102,6 +108,10 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
|||||||
|
|
||||||
realtimeTimeout = millis() + timeoutMs;
|
realtimeTimeout = millis() + timeoutMs;
|
||||||
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
|
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;
|
realtimeMode = md;
|
||||||
|
|
||||||
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(scaledBri(255));
|
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(scaledBri(255));
|
||||||
@ -567,7 +577,7 @@ uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) {
|
|||||||
// buffer - a buffer of at least length*4 bytes long
|
// buffer - a buffer of at least length*4 bytes long
|
||||||
// isRGBW - true if the buffer contains 4 components per pixel
|
// isRGBW - true if the buffer contains 4 components per pixel
|
||||||
//
|
//
|
||||||
void realtimeBoroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) {
|
void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) {
|
||||||
|
|
||||||
WiFiUDP ddpUdp;
|
WiFiUDP ddpUdp;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ void sendSysInfoUDP();
|
|||||||
// buffer - a buffer of at least length*3 or length*4 bytes long
|
// buffer - a buffer of at least length*3 or length*4 bytes long
|
||||||
// length - the number of pixels
|
// length - the number of pixels
|
||||||
// isRGBW - true if the buffer contains 4 components per pixel
|
// isRGBW - true if the buffer contains 4 components per pixel
|
||||||
void realtimeBoroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW);
|
void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW);
|
||||||
|
|
||||||
#define DDP_PORT 4048
|
#define DDP_PORT 4048
|
||||||
|
|
||||||
|
@ -86,6 +86,10 @@
|
|||||||
#include "../usermods/rgb-rotary-encoder/rgb-rotary-encoder.h"
|
#include "../usermods/rgb-rotary-encoder/rgb-rotary-encoder.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_ST7789_DISPLAY
|
||||||
|
#include "../usermods/ST7789_display/ST7789_Display.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void registerUsermods()
|
void registerUsermods()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -167,4 +171,8 @@ void registerUsermods()
|
|||||||
#ifdef RGB_ROTARY_ENCODER
|
#ifdef RGB_ROTARY_ENCODER
|
||||||
usermods.add(new RgbRotaryEncoderUsermod());
|
usermods.add(new RgbRotaryEncoderUsermod());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_ST7789_DISPLAY
|
||||||
|
usermods.add(new St7789DisplayUsermod());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
187
wled00/wled.cpp
187
wled00/wled.cpp
@ -8,6 +8,90 @@
|
|||||||
#include "soc/rtc_cntl_reg.h"
|
#include "soc/rtc_cntl_reg.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WLED_USE_ETHERNET
|
||||||
|
// The following six pins are neither configurable nor
|
||||||
|
// can they be re-assigned through IOMUX / GPIO matrix.
|
||||||
|
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
||||||
|
const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT] = {
|
||||||
|
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
|
||||||
|
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
|
||||||
|
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
|
||||||
|
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
|
||||||
|
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
|
||||||
|
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
|
||||||
|
};
|
||||||
|
|
||||||
|
const ethernet_settings ethernetBoards[] = {
|
||||||
|
// None
|
||||||
|
{
|
||||||
|
},
|
||||||
|
|
||||||
|
// WT32-EHT01
|
||||||
|
// Please note, from my testing only these pins work for LED outputs:
|
||||||
|
// IO2, IO4, IO12, IO14, IO15
|
||||||
|
// These pins do not appear to work from my testing:
|
||||||
|
// IO35, IO36, IO39
|
||||||
|
{
|
||||||
|
1, // eth_address,
|
||||||
|
16, // eth_power,
|
||||||
|
23, // eth_mdc,
|
||||||
|
18, // eth_mdio,
|
||||||
|
ETH_PHY_LAN8720, // eth_type,
|
||||||
|
ETH_CLOCK_GPIO0_IN // eth_clk_mode
|
||||||
|
},
|
||||||
|
|
||||||
|
// ESP32-POE
|
||||||
|
{
|
||||||
|
0, // eth_address,
|
||||||
|
12, // eth_power,
|
||||||
|
23, // eth_mdc,
|
||||||
|
18, // eth_mdio,
|
||||||
|
ETH_PHY_LAN8720, // eth_type,
|
||||||
|
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||||
|
},
|
||||||
|
|
||||||
|
// WESP32
|
||||||
|
{
|
||||||
|
0, // eth_address,
|
||||||
|
-1, // eth_power,
|
||||||
|
16, // eth_mdc,
|
||||||
|
17, // eth_mdio,
|
||||||
|
ETH_PHY_LAN8720, // eth_type,
|
||||||
|
ETH_CLOCK_GPIO0_IN // eth_clk_mode
|
||||||
|
},
|
||||||
|
|
||||||
|
// QuinLed-ESP32-Ethernet
|
||||||
|
{
|
||||||
|
0, // eth_address,
|
||||||
|
5, // eth_power,
|
||||||
|
23, // eth_mdc,
|
||||||
|
18, // eth_mdio,
|
||||||
|
ETH_PHY_LAN8720, // eth_type,
|
||||||
|
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||||
|
},
|
||||||
|
|
||||||
|
// TwilightLord-ESP32 Ethernet Shield
|
||||||
|
{
|
||||||
|
0, // eth_address,
|
||||||
|
5, // eth_power,
|
||||||
|
23, // eth_mdc,
|
||||||
|
18, // eth_mdio,
|
||||||
|
ETH_PHY_LAN8720, // eth_type,
|
||||||
|
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||||
|
},
|
||||||
|
|
||||||
|
// ESP3DEUXQuattro
|
||||||
|
{
|
||||||
|
1, // eth_address,
|
||||||
|
-1, // eth_power,
|
||||||
|
23, // eth_mdc,
|
||||||
|
18, // eth_mdio,
|
||||||
|
ETH_PHY_LAN8720, // eth_type,
|
||||||
|
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main WLED class implementation. Mostly initialization and connection logic
|
* Main WLED class implementation. Mostly initialization and connection logic
|
||||||
*/
|
*/
|
||||||
@ -120,6 +204,10 @@ void WiFiEvent(WiFiEvent_t event)
|
|||||||
|
|
||||||
void WLED::loop()
|
void WLED::loop()
|
||||||
{
|
{
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
|
static unsigned long maxUsermodMillis = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
handleTime();
|
handleTime();
|
||||||
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
||||||
handleConnection();
|
handleConnection();
|
||||||
@ -130,7 +218,15 @@ void WLED::loop()
|
|||||||
handleDMX();
|
handleDMX();
|
||||||
#endif
|
#endif
|
||||||
userLoop();
|
userLoop();
|
||||||
|
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
|
unsigned long usermodMillis = millis();
|
||||||
|
#endif
|
||||||
usermods.loop();
|
usermods.loop();
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
|
usermodMillis = millis() - usermodMillis;
|
||||||
|
if (usermodMillis > maxUsermodMillis) maxUsermodMillis = usermodMillis;
|
||||||
|
#endif
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
handleIO();
|
handleIO();
|
||||||
@ -159,7 +255,9 @@ void WLED::loop()
|
|||||||
yield();
|
yield();
|
||||||
|
|
||||||
handleHue();
|
handleHue();
|
||||||
|
#ifndef WLED_DISABLE_BLYNK
|
||||||
handleBlynk();
|
handleBlynk();
|
||||||
|
#endif
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
|
|
||||||
@ -197,10 +295,12 @@ void WLED::loop()
|
|||||||
DEBUG_PRINTLN(F("Re-init busses."));
|
DEBUG_PRINTLN(F("Re-init busses."));
|
||||||
busses.removeAll();
|
busses.removeAll();
|
||||||
uint32_t mem = 0;
|
uint32_t mem = 0;
|
||||||
strip.isRgbw = false;
|
|
||||||
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
|
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
|
||||||
if (busConfigs[i] == nullptr) break;
|
if (busConfigs[i] == nullptr) break;
|
||||||
|
mem += BusManager::memUsage(*busConfigs[i]);
|
||||||
|
if (mem <= MAX_LED_MEMORY) busses.add(*busConfigs[i]);
|
||||||
|
/*
|
||||||
|
// this is done in strip.finalizeInit()
|
||||||
if (busConfigs[i]->adjustBounds(ledCount)) {
|
if (busConfigs[i]->adjustBounds(ledCount)) {
|
||||||
mem += busses.memUsage(*busConfigs[i]);
|
mem += busses.memUsage(*busConfigs[i]);
|
||||||
if (mem <= MAX_LED_MEMORY) {
|
if (mem <= MAX_LED_MEMORY) {
|
||||||
@ -211,20 +311,20 @@ void WLED::loop()
|
|||||||
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(busConfigs[i]->type);
|
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(busConfigs[i]->type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||||
}
|
}
|
||||||
strip.finalizeInit(ledCount);
|
strip.finalizeInit();
|
||||||
yield();
|
yield();
|
||||||
serializeConfig();
|
serializeConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
handleWs();
|
handleWs();
|
||||||
handleStatusLED();
|
|
||||||
|
|
||||||
// DEBUG serial logging
|
// DEBUG serial logging
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
if (millis() - debugTime > 9999) {
|
if (millis() - debugTime > 29999) {
|
||||||
DEBUG_PRINTLN(F("---DEBUG INFO---"));
|
DEBUG_PRINTLN(F("---DEBUG INFO---"));
|
||||||
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
|
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
|
||||||
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
|
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
|
||||||
@ -236,17 +336,19 @@ void WLED::loop()
|
|||||||
} else
|
} else
|
||||||
DEBUG_PRINTLN(F("No PSRAM"));
|
DEBUG_PRINTLN(F("No PSRAM"));
|
||||||
#endif
|
#endif
|
||||||
DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status());
|
DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status());
|
||||||
|
|
||||||
if (WiFi.status() != lastWifiState) {
|
if (WiFi.status() != lastWifiState) {
|
||||||
wifiStateChangedTime = millis();
|
wifiStateChangedTime = millis();
|
||||||
}
|
}
|
||||||
lastWifiState = WiFi.status();
|
lastWifiState = WiFi.status();
|
||||||
DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime);
|
DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime);
|
||||||
DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime);
|
DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime);
|
||||||
DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP());
|
DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP());
|
||||||
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 10);
|
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 60);
|
||||||
|
DEBUG_PRINT(F("Max UM time[ms]: ")); DEBUG_PRINTLN(maxUsermodMillis);
|
||||||
loops = 0;
|
loops = 0;
|
||||||
|
maxUsermodMillis = 0;
|
||||||
debugTime = millis();
|
debugTime = millis();
|
||||||
}
|
}
|
||||||
loops++;
|
loops++;
|
||||||
@ -315,14 +417,6 @@ void WLED::setup()
|
|||||||
DEBUG_PRINTLN(F("Reading config"));
|
DEBUG_PRINTLN(F("Reading config"));
|
||||||
deserializeConfigFromFS();
|
deserializeConfigFromFS();
|
||||||
|
|
||||||
#if STATUSLED
|
|
||||||
if (!pinManager.isPinAllocated(STATUSLED)) {
|
|
||||||
// NOTE: Special case: The status LED should *NOT* be allocated.
|
|
||||||
// See comments in handleStatusLed().
|
|
||||||
pinMode(STATUSLED, OUTPUT);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DEBUG_PRINTLN(F("Initializing strip"));
|
DEBUG_PRINTLN(F("Initializing strip"));
|
||||||
beginStrip();
|
beginStrip();
|
||||||
|
|
||||||
@ -336,9 +430,12 @@ void WLED::setup()
|
|||||||
WiFi.onEvent(WiFiEvent);
|
WiFi.onEvent(WiFiEvent);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_ADALIGHT
|
#ifdef WLED_ENABLE_ADALIGHT // reserve GPIO3 (RX) pin for ADALight
|
||||||
if (!pinManager.isPinAllocated(3)) {
|
if (!pinManager.isPinAllocated(3)) {
|
||||||
Serial.println(F("Ada"));
|
Serial.println(F("Ada"));
|
||||||
|
pinManager.allocatePin(3,false);
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTLN(F("ADALight disabled due to GPIO3 being used."));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -388,22 +485,20 @@ void WLED::setup()
|
|||||||
void WLED::beginStrip()
|
void WLED::beginStrip()
|
||||||
{
|
{
|
||||||
// Initialize NeoPixel Strip and button
|
// Initialize NeoPixel Strip and button
|
||||||
|
strip.finalizeInit(); // busses created during deserializeConfig()
|
||||||
if (ledCount > MAX_LEDS || ledCount == 0)
|
strip.populateDefaultSegments();
|
||||||
ledCount = 30;
|
|
||||||
|
|
||||||
strip.finalizeInit(ledCount);
|
|
||||||
strip.setBrightness(0);
|
strip.setBrightness(0);
|
||||||
strip.setShowCallback(handleOverlayDraw);
|
strip.setShowCallback(handleOverlayDraw);
|
||||||
|
|
||||||
if (bootPreset > 0) {
|
if (turnOnAtBoot) {
|
||||||
applyPreset(bootPreset, CALL_MODE_INIT);
|
|
||||||
} else if (turnOnAtBoot) {
|
|
||||||
if (briS > 0) bri = briS;
|
if (briS > 0) bri = briS;
|
||||||
else if (bri == 0) bri = 128;
|
else if (bri == 0) bri = 128;
|
||||||
} else {
|
} else {
|
||||||
briLast = briS; bri = 0;
|
briLast = briS; bri = 0;
|
||||||
}
|
}
|
||||||
|
if (bootPreset > 0) {
|
||||||
|
applyPreset(bootPreset, CALL_MODE_INIT);
|
||||||
|
}
|
||||||
colorUpdated(CALL_MODE_INIT);
|
colorUpdated(CALL_MODE_INIT);
|
||||||
|
|
||||||
// init relay pin
|
// init relay pin
|
||||||
@ -726,39 +821,3 @@ void WLED::handleConnection()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If status LED pin is allocated for other uses, does nothing
|
|
||||||
// else blink at 1Hz when WLED_CONNECTED is false (no WiFi, ?? no Ethernet ??)
|
|
||||||
// else blink at 2Hz when MQTT is enabled but not connected
|
|
||||||
// else turn the status LED off
|
|
||||||
void WLED::handleStatusLED()
|
|
||||||
{
|
|
||||||
#if STATUSLED
|
|
||||||
static unsigned long ledStatusLastMillis = 0;
|
|
||||||
static unsigned short ledStatusType = 0; // current status type - corresponds to number of blinks per second
|
|
||||||
static bool ledStatusState = 0; // the current LED state
|
|
||||||
|
|
||||||
if (pinManager.isPinAllocated(STATUSLED)) {
|
|
||||||
return; //lower priority if something else uses the same pin
|
|
||||||
}
|
|
||||||
|
|
||||||
ledStatusType = WLED_CONNECTED ? 0 : 2;
|
|
||||||
if (mqttEnabled && ledStatusType != 2) { // Wi-Fi takes precendence over MQTT
|
|
||||||
ledStatusType = WLED_MQTT_CONNECTED ? 0 : 4;
|
|
||||||
}
|
|
||||||
if (ledStatusType) {
|
|
||||||
if (millis() - ledStatusLastMillis >= (1000/ledStatusType)) {
|
|
||||||
ledStatusLastMillis = millis();
|
|
||||||
ledStatusState = ledStatusState ? 0 : 1;
|
|
||||||
digitalWrite(STATUSLED, ledStatusState);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#ifdef STATUSLEDINVERTED
|
|
||||||
digitalWrite(STATUSLED, HIGH);
|
|
||||||
#else
|
|
||||||
digitalWrite(STATUSLED, LOW);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
/*
|
/*
|
||||||
Main sketch, global variable declarations
|
Main sketch, global variable declarations
|
||||||
@title WLED project sketch
|
@title WLED project sketch
|
||||||
@version 0.13.0-b2
|
@version 0.13.0-bl2
|
||||||
@author Christian Schwinne
|
@author Christian Schwinne
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2109100
|
#define VERSION 2109191
|
||||||
|
|
||||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
@ -31,9 +31,11 @@
|
|||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
#define WLED_ENABLE_MQTT // saves 12kb
|
#define WLED_ENABLE_MQTT // saves 12kb
|
||||||
#endif
|
#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_DMX // uses 3.5kb (use LEDPIN other than 2)
|
||||||
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
#ifndef WLED_DISABLE_LOXONE
|
||||||
|
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||||
|
#endif
|
||||||
#ifndef WLED_DISABLE_WEBSOCKETS
|
#ifndef WLED_DISABLE_WEBSOCKETS
|
||||||
#define WLED_ENABLE_WEBSOCKETS
|
#define WLED_ENABLE_WEBSOCKETS
|
||||||
#endif
|
#endif
|
||||||
@ -136,6 +138,9 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
|||||||
|
|
||||||
#include "fcn_declare.h"
|
#include "fcn_declare.h"
|
||||||
#include "html_ui.h"
|
#include "html_ui.h"
|
||||||
|
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||||
|
#include "html_simple.h"
|
||||||
|
#endif
|
||||||
#include "html_settings.h"
|
#include "html_settings.h"
|
||||||
#include "html_other.h"
|
#include "html_other.h"
|
||||||
#include "FX.h"
|
#include "FX.h"
|
||||||
@ -225,11 +230,7 @@ WLED_GLOBAL bool rlyMde _INIT(true);
|
|||||||
WLED_GLOBAL bool rlyMde _INIT(RLYMDE);
|
WLED_GLOBAL bool rlyMde _INIT(RLYMDE);
|
||||||
#endif
|
#endif
|
||||||
#ifndef IRPIN
|
#ifndef IRPIN
|
||||||
#ifdef WLED_DISABLE_INFRARED
|
WLED_GLOBAL int8_t irPin _INIT(-1);
|
||||||
WLED_GLOBAL int8_t irPin _INIT(-1);
|
|
||||||
#else
|
|
||||||
WLED_GLOBAL int8_t irPin _INIT(4);
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
WLED_GLOBAL int8_t irPin _INIT(IRPIN);
|
WLED_GLOBAL int8_t irPin _INIT(IRPIN);
|
||||||
#endif
|
#endif
|
||||||
@ -264,9 +265,9 @@ WLED_GLOBAL bool noWifiSleep _INIT(false);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// LED CONFIG
|
// LED CONFIG
|
||||||
WLED_GLOBAL uint16_t ledCount _INIT(DEFAULT_LED_COUNT); // overcurrent prevented by ABL
|
WLED_GLOBAL uint16_t ledCount _INIT(0); // overcurrent prevented by ABL (filled in cfg.cpp, set.cpp or FX_fcn.cpp)
|
||||||
WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up
|
WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up
|
||||||
WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up
|
WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up
|
||||||
|
|
||||||
//if true, a segment per bus will be created on boot and LED settings save
|
//if true, a segment per bus will be created on boot and LED settings save
|
||||||
//if false, only one segment spanning the total LEDs is created,
|
//if false, only one segment spanning the total LEDs is created,
|
||||||
@ -288,6 +289,8 @@ WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (t
|
|||||||
// User Interface CONFIG
|
// User Interface CONFIG
|
||||||
WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module
|
WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module
|
||||||
WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise
|
WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise
|
||||||
|
WLED_GLOBAL bool simplifiedUI _INIT(false); // enable simplified UI
|
||||||
|
WLED_GLOBAL byte cacheInvalidate _INIT(0); // used to invalidate browser cache when switching from regular to simplified UI
|
||||||
|
|
||||||
// Sync CONFIG
|
// Sync CONFIG
|
||||||
WLED_GLOBAL NodesMap Nodes;
|
WLED_GLOBAL NodesMap Nodes;
|
||||||
@ -566,7 +569,7 @@ WLED_GLOBAL JsonDocument* fileDoc;
|
|||||||
WLED_GLOBAL bool doCloseFile _INIT(false);
|
WLED_GLOBAL bool doCloseFile _INIT(false);
|
||||||
|
|
||||||
// presets
|
// presets
|
||||||
WLED_GLOBAL int16_t currentPreset _INIT(-1);
|
WLED_GLOBAL int8_t currentPreset _INIT(-1);
|
||||||
|
|
||||||
WLED_GLOBAL byte errorFlag _INIT(0);
|
WLED_GLOBAL byte errorFlag _INIT(0);
|
||||||
|
|
||||||
@ -599,7 +602,6 @@ WLED_GLOBAL bool doInitBusses _INIT(false);
|
|||||||
// Usermod manager
|
// Usermod manager
|
||||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||||
|
|
||||||
|
|
||||||
// enable additional debug output
|
// enable additional debug output
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
@ -629,7 +631,7 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
|||||||
WLED_GLOBAL unsigned long debugTime _INIT(0);
|
WLED_GLOBAL unsigned long debugTime _INIT(0);
|
||||||
WLED_GLOBAL int lastWifiState _INIT(3);
|
WLED_GLOBAL int lastWifiState _INIT(3);
|
||||||
WLED_GLOBAL unsigned long wifiStateChangedTime _INIT(0);
|
WLED_GLOBAL unsigned long wifiStateChangedTime _INIT(0);
|
||||||
WLED_GLOBAL int loops _INIT(0);
|
WLED_GLOBAL unsigned long loops _INIT(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
@ -666,6 +668,5 @@ public:
|
|||||||
void initAP(bool resetAP = false);
|
void initAP(bool resetAP = false);
|
||||||
void initConnection();
|
void initConnection();
|
||||||
void initInterfaces();
|
void initInterfaces();
|
||||||
void handleStatusLED();
|
|
||||||
};
|
};
|
||||||
#endif // WLED_H
|
#endif // WLED_H
|
||||||
|
@ -1,20 +1,9 @@
|
|||||||
#ifndef WLED_ETHERNET_H
|
#ifndef WLED_ETHERNET_H
|
||||||
#define WLED_ETHERNET_H
|
#define WLED_ETHERNET_H
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
|
||||||
#include "pin_manager.h"
|
#include "pin_manager.h"
|
||||||
|
|
||||||
// The following six pins are neither configurable nor
|
#ifdef WLED_USE_ETHERNET
|
||||||
// can they be re-assigned through IOMUX / GPIO matrix.
|
|
||||||
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
|
||||||
const managed_pin_type esp32_nonconfigurable_ethernet_pins[6] = {
|
|
||||||
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
|
|
||||||
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
|
|
||||||
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
|
|
||||||
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
|
|
||||||
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
|
|
||||||
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
|
|
||||||
};
|
|
||||||
|
|
||||||
// For ESP32, the remaining five pins are at least somewhat configurable.
|
// For ESP32, the remaining five pins are at least somewhat configurable.
|
||||||
// eth_address is in range [0..31], indicates which PHY (MAC?) address should be allocated to the interface
|
// eth_address is in range [0..31], indicates which PHY (MAC?) address should be allocated to the interface
|
||||||
@ -37,74 +26,10 @@ typedef struct EthernetSettings {
|
|||||||
eth_clock_mode_t eth_clk_mode;
|
eth_clock_mode_t eth_clk_mode;
|
||||||
} ethernet_settings;
|
} ethernet_settings;
|
||||||
|
|
||||||
ethernet_settings ethernetBoards[] = {
|
extern const ethernet_settings ethernetBoards[];
|
||||||
// None
|
|
||||||
{
|
|
||||||
},
|
|
||||||
|
|
||||||
// WT32-EHT01
|
|
||||||
// (*) NOTE: silkscreen on board revision v1.2 may be wrong:
|
|
||||||
// silkscreen on v1.2 says IO35, but appears to be IO5
|
|
||||||
// silkscreen on v1.2 says RXD, and appears to be IO35
|
|
||||||
{
|
|
||||||
1, // eth_address,
|
|
||||||
16, // eth_power,
|
|
||||||
23, // eth_mdc,
|
|
||||||
18, // eth_mdio,
|
|
||||||
ETH_PHY_LAN8720, // eth_type,
|
|
||||||
ETH_CLOCK_GPIO0_IN // eth_clk_mode
|
|
||||||
},
|
|
||||||
|
|
||||||
// ESP32-POE
|
#define WLED_ETH_RSVD_PINS_COUNT 6
|
||||||
{
|
extern const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT];
|
||||||
0, // eth_address,
|
|
||||||
12, // eth_power,
|
|
||||||
23, // eth_mdc,
|
|
||||||
18, // eth_mdio,
|
|
||||||
ETH_PHY_LAN8720, // eth_type,
|
|
||||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
|
||||||
},
|
|
||||||
|
|
||||||
// WESP32
|
|
||||||
{
|
|
||||||
0, // eth_address,
|
|
||||||
-1, // eth_power,
|
|
||||||
16, // eth_mdc,
|
|
||||||
17, // eth_mdio,
|
|
||||||
ETH_PHY_LAN8720, // eth_type,
|
|
||||||
ETH_CLOCK_GPIO0_IN // eth_clk_mode
|
|
||||||
},
|
|
||||||
|
|
||||||
// QuinLed-ESP32-Ethernet
|
|
||||||
{
|
|
||||||
0, // eth_address,
|
|
||||||
5, // eth_power,
|
|
||||||
23, // eth_mdc,
|
|
||||||
18, // eth_mdio,
|
|
||||||
ETH_PHY_LAN8720, // eth_type,
|
|
||||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
|
||||||
},
|
|
||||||
|
|
||||||
// TwilightLord-ESP32 Ethernet Shield
|
|
||||||
{
|
|
||||||
0, // eth_address,
|
|
||||||
5, // eth_power,
|
|
||||||
23, // eth_mdc,
|
|
||||||
18, // eth_mdio,
|
|
||||||
ETH_PHY_LAN8720, // eth_type,
|
|
||||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
|
||||||
},
|
|
||||||
|
|
||||||
// ESP3DEUXQuattro
|
|
||||||
{
|
|
||||||
1, // eth_address,
|
|
||||||
-1, // eth_power,
|
|
||||||
23, // eth_mdc,
|
|
||||||
18, // eth_mdio,
|
|
||||||
ETH_PHY_LAN8720, // eth_type,
|
|
||||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -80,6 +80,43 @@ float asin_t(float x) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//https://stackoverflow.com/a/42542593
|
||||||
|
#define A 0.0776509570923569
|
||||||
|
#define B -0.287434475393028
|
||||||
|
#define C ((HALF_PI/2) - A - B)
|
||||||
|
|
||||||
|
//polynominal factors for approximation between 1 and 5
|
||||||
|
#define C0 0.089494f
|
||||||
|
#define C1 0.974207f
|
||||||
|
#define C2 -0.326175f
|
||||||
|
#define C3 0.05375f
|
||||||
|
#define C4 -0.003445f
|
||||||
|
|
||||||
|
float atan_t(float x) {
|
||||||
|
bool neg = (x < 0);
|
||||||
|
#ifdef WLED_DEBUG_MATH
|
||||||
|
float xinput = x;
|
||||||
|
#endif
|
||||||
|
x = std::abs(x);
|
||||||
|
float res;
|
||||||
|
if (x > 5.0f) { //atan(x) converges to pi/2 - (1/x) for large values
|
||||||
|
res = HALF_PI - (1.0f/x);
|
||||||
|
}
|
||||||
|
else if (x > 1.0f) { //1 < x < 5
|
||||||
|
float xx = x * x;
|
||||||
|
res = (C4*xx*xx)+(C3*xx*x)+(C2*xx)+(C1*x)+C0;
|
||||||
|
} else { //this approximation is only for x <= 1
|
||||||
|
float xx = x * x;
|
||||||
|
res = ((A*xx + B)*xx + C)*x;
|
||||||
|
}
|
||||||
|
if (neg) res = -res;
|
||||||
|
#ifdef WLED_DEBUG_MATH
|
||||||
|
Serial.printf("atan,%f,%f,%f\n",xinput,res,atan(xinput));
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
*/
|
||||||
//https://stackoverflow.com/a/42542593
|
//https://stackoverflow.com/a/42542593
|
||||||
#define A 0.0776509570923569
|
#define A 0.0776509570923569
|
||||||
#define B -0.287434475393028
|
#define B -0.287434475393028
|
||||||
@ -135,4 +172,4 @@ float fmod_t(float num, float denom) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -114,7 +114,7 @@ void handleSerial()
|
|||||||
if (!realtimeOverride) setRealtimePixel(pixel++, red, green, blue, 0);
|
if (!realtimeOverride) setRealtimePixel(pixel++, red, green, blue, 0);
|
||||||
if (--count > 0) state = AdaState::Data_Red;
|
if (--count > 0) state = AdaState::Data_Red;
|
||||||
else {
|
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);
|
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
|
||||||
|
|
||||||
if (!realtimeOverride) strip.show();
|
if (!realtimeOverride) strip.show();
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
* Integrated HTTP web server page declarations
|
* Integrated HTTP web server page declarations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request);
|
||||||
|
void setStaticContentCacheHeaders(AsyncWebServerResponse *response);
|
||||||
|
|
||||||
//Is this an IP?
|
//Is this an IP?
|
||||||
bool isIp(String str) {
|
bool isIp(String str) {
|
||||||
for (size_t i = 0; i < str.length(); i++) {
|
for (size_t i = 0; i < str.length(); i++) {
|
||||||
@ -16,7 +19,7 @@ bool isIp(String str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){
|
void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||||
if(!index){
|
if (!index) {
|
||||||
request->_tempFile = WLED_FS.open(filename, "w");
|
request->_tempFile = WLED_FS.open(filename, "w");
|
||||||
DEBUG_PRINT("Uploading ");
|
DEBUG_PRINT("Uploading ");
|
||||||
DEBUG_PRINTLN(filename);
|
DEBUG_PRINTLN(filename);
|
||||||
@ -25,9 +28,10 @@ void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t
|
|||||||
if (len) {
|
if (len) {
|
||||||
request->_tempFile.write(data,len);
|
request->_tempFile.write(data,len);
|
||||||
}
|
}
|
||||||
if(final){
|
if (final) {
|
||||||
request->_tempFile.close();
|
request->_tempFile.close();
|
||||||
request->send(200, "text/plain", F("File Uploaded!"));
|
request->send(200, "text/plain", F("File Uploaded!"));
|
||||||
|
cacheInvalidate++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +167,15 @@ void initServer()
|
|||||||
size_t len, bool final) {handleUpload(request, filename, index, data, len, final);}
|
size_t len, bool final) {handleUpload(request, filename, index, data, len, final);}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
server.on("/simple.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
if (handleFileRead(request, "/simple.htm")) return;
|
||||||
|
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_simple, PAGE_simple_L);
|
||||||
|
response->addHeader(F("Content-Encoding"),"gzip");
|
||||||
|
setStaticContentCacheHeaders(response);
|
||||||
|
request->send(response);
|
||||||
|
});
|
||||||
|
|
||||||
//if OTA is allowed
|
//if OTA is allowed
|
||||||
if (!otaLock){
|
if (!otaLock){
|
||||||
#ifdef WLED_ENABLE_FS_EDITOR
|
#ifdef WLED_ENABLE_FS_EDITOR
|
||||||
@ -287,6 +300,8 @@ bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
|
void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
|
||||||
{
|
{
|
||||||
|
char tmp[12];
|
||||||
|
// https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c
|
||||||
#ifndef WLED_DEBUG
|
#ifndef WLED_DEBUG
|
||||||
//this header name is misleading, "no-cache" will not disable cache,
|
//this header name is misleading, "no-cache" will not disable cache,
|
||||||
//it just revalidates on every load using the "If-None-Match" header with the last ETag value
|
//it just revalidates on every load using the "If-None-Match" header with the last ETag value
|
||||||
@ -294,7 +309,8 @@ void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
|
|||||||
#else
|
#else
|
||||||
response->addHeader(F("Cache-Control"),"no-store,max-age=0"); // prevent caching if debug build
|
response->addHeader(F("Cache-Control"),"no-store,max-age=0"); // prevent caching if debug build
|
||||||
#endif
|
#endif
|
||||||
response->addHeader(F("ETag"), String(VERSION));
|
sprintf_P(tmp, PSTR("%8d-%02x"), VERSION, cacheInvalidate);
|
||||||
|
response->addHeader(F("ETag"), tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serveIndex(AsyncWebServerRequest* request)
|
void serveIndex(AsyncWebServerRequest* request)
|
||||||
@ -303,7 +319,13 @@ void serveIndex(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||||
|
|
||||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_index, PAGE_index_L);
|
AsyncWebServerResponse *response;
|
||||||
|
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||||
|
if (simplifiedUI)
|
||||||
|
response = request->beginResponse_P(200, "text/html", PAGE_simple, PAGE_simple_L);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
response = request->beginResponse_P(200, "text/html", PAGE_index, PAGE_index_L);
|
||||||
|
|
||||||
response->addHeader(F("Content-Encoding"),"gzip");
|
response->addHeader(F("Content-Encoding"),"gzip");
|
||||||
setStaticContentCacheHeaders(response);
|
setStaticContentCacheHeaders(response);
|
||||||
|
@ -16,9 +16,11 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
if(type == WS_EVT_CONNECT){
|
if(type == WS_EVT_CONNECT){
|
||||||
//client connected
|
//client connected
|
||||||
sendDataWs(client);
|
sendDataWs(client);
|
||||||
|
DEBUG_PRINTLN(F("WS client connected."));
|
||||||
} else if(type == WS_EVT_DISCONNECT){
|
} else if(type == WS_EVT_DISCONNECT){
|
||||||
//client disconnected
|
//client disconnected
|
||||||
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
||||||
|
DEBUG_PRINTLN(F("WS client disconnected."));
|
||||||
} else if(type == WS_EVT_DATA){
|
} else if(type == WS_EVT_DATA){
|
||||||
//data packet
|
//data packet
|
||||||
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||||
@ -39,6 +41,11 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
JsonObject root = jsonBuffer.as<JsonObject>();
|
JsonObject root = jsonBuffer.as<JsonObject>();
|
||||||
if (error || root.isNull()) return;
|
if (error || root.isNull()) return;
|
||||||
|
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
|
DEBUG_PRINT(F("Incoming WS: "));
|
||||||
|
serializeJson(root,Serial);
|
||||||
|
DEBUG_PRINTLN();
|
||||||
|
#endif
|
||||||
if (root["v"] && root.size() == 1) {
|
if (root["v"] && root.size() == 1) {
|
||||||
//if the received value is just "{"v":true}", send only to this client
|
//if the received value is just "{"v":true}", send only to this client
|
||||||
verboseResponse = true;
|
verboseResponse = true;
|
||||||
@ -76,12 +83,15 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DEBUG_PRINTLN(F("WS multipart message."));
|
||||||
}
|
}
|
||||||
} else if(type == WS_EVT_ERROR){
|
} else if(type == WS_EVT_ERROR){
|
||||||
//error was received from the other end
|
//error was received from the other end
|
||||||
|
DEBUG_PRINTLN(F("WS error."));
|
||||||
|
|
||||||
} else if(type == WS_EVT_PONG){
|
} else if(type == WS_EVT_PONG){
|
||||||
//pong message was received (in response to a ping request maybe)
|
//pong message was received (in response to a ping request maybe)
|
||||||
|
DEBUG_PRINTLN(F("WS pong."));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,13 +110,22 @@ void sendDataWs(AsyncWebSocketClient * client)
|
|||||||
size_t len = measureJson(doc);
|
size_t len = measureJson(doc);
|
||||||
buffer = ws.makeBuffer(len);
|
buffer = ws.makeBuffer(len);
|
||||||
if (!buffer) return; //out of memory
|
if (!buffer) return; //out of memory
|
||||||
|
/*
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
|
DEBUG_PRINT(F("Outgoing WS: "));
|
||||||
|
serializeJson(doc,Serial);
|
||||||
|
DEBUG_PRINTLN();
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
serializeJson(doc, (char *)buffer->get(), len +1);
|
serializeJson(doc, (char *)buffer->get(), len +1);
|
||||||
}
|
}
|
||||||
|
DEBUG_PRINT(F("Sending WS data "));
|
||||||
if (client) {
|
if (client) {
|
||||||
client->text(buffer);
|
client->text(buffer);
|
||||||
|
DEBUG_PRINTLN(F("to a single client."));
|
||||||
} else {
|
} else {
|
||||||
ws.textAll(buffer);
|
ws.textAll(buffer);
|
||||||
|
DEBUG_PRINTLN(F("to multiple clients."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
171
wled00/xml.cpp
171
wled00/xml.cpp
@ -1,4 +1,5 @@
|
|||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
#include "wled_ethernet.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sending XML status files to client
|
* Sending XML status files to client
|
||||||
@ -158,24 +159,16 @@ void sappends(char stype, const char* key, char* val)
|
|||||||
{
|
{
|
||||||
switch(stype)
|
switch(stype)
|
||||||
{
|
{
|
||||||
case 's': { //string (we can interpret val as char*)
|
case 's': {//string (we can interpret val as char*)
|
||||||
|
String buf = val;
|
||||||
|
//convert "%" to "%%" to make EspAsyncWebServer happy
|
||||||
|
buf.replace("%","%%");
|
||||||
oappend("d.Sf.");
|
oappend("d.Sf.");
|
||||||
oappend(key);
|
oappend(key);
|
||||||
oappend(".value=\"");
|
oappend(".value=\"");
|
||||||
//convert "%" to "%%" to make EspAsyncWebServer happy
|
oappend(buf.c_str());
|
||||||
char buf[130];
|
|
||||||
uint8_t len = strlen(val) +1;
|
|
||||||
uint8_t s = 0;
|
|
||||||
for (uint8_t i = 0; i < len; i++) {
|
|
||||||
buf[i+s] = val[i];
|
|
||||||
if (val[i] == '%') {
|
|
||||||
s++; buf[i+s] = '%';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
oappend(buf);
|
|
||||||
oappend("\";");
|
oappend("\";");
|
||||||
break; }
|
break;}
|
||||||
case 'm': //message
|
case 'm': //message
|
||||||
oappend(SET_F("d.getElementsByClassName"));
|
oappend(SET_F("d.getElementsByClassName"));
|
||||||
oappend(key);
|
oappend(key);
|
||||||
@ -186,6 +179,52 @@ void sappends(char stype, const char* key, char* val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void extractPin(JsonObject &obj, const char *key) {
|
||||||
|
if (obj[key].is<JsonArray>()) {
|
||||||
|
JsonArray pins = obj[key].as<JsonArray>();
|
||||||
|
for (JsonVariant pv : pins) {
|
||||||
|
if (pv.as<int>() > -1) { oappend(","); oappendi(pv.as<int>()); }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (obj[key].as<int>() > -1) { oappend(","); oappendi(obj[key].as<int>()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// oappens used pins by recursively scanning JsonObject
|
||||||
|
void fillUMPins(JsonObject &mods)
|
||||||
|
{
|
||||||
|
for (JsonPair kv : mods) {
|
||||||
|
// kv.key() is usermod name or subobject key
|
||||||
|
// kv.value() is object itself
|
||||||
|
JsonObject obj = kv.value();
|
||||||
|
if (!obj.isNull()) {
|
||||||
|
// element is an JsonObject
|
||||||
|
if (!obj["pin"].isNull()) {
|
||||||
|
extractPin(obj, "pin");
|
||||||
|
} else {
|
||||||
|
// scan keys (just one level deep as is possible with usermods)
|
||||||
|
for (JsonPair so : obj) {
|
||||||
|
const char *key = so.key().c_str();
|
||||||
|
if (strstr(key, "pin")) {
|
||||||
|
// we found a key containing "pin" substring
|
||||||
|
if (strlen(strstr(key, "pin")) == 3) {
|
||||||
|
// and it is at the end, we found another pin
|
||||||
|
extractPin(obj, key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!obj[so.key()].is<JsonObject>()) continue;
|
||||||
|
JsonObject subObj = obj[so.key()];
|
||||||
|
if (!subObj["pin"].isNull()) {
|
||||||
|
// get pins from subobject
|
||||||
|
extractPin(subObj, "pin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//get values for settings form in javascript
|
//get values for settings form in javascript
|
||||||
void getSettingsJS(byte subPage, char* dest)
|
void getSettingsJS(byte subPage, char* dest)
|
||||||
@ -198,7 +237,8 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
|
|
||||||
if (subPage <1 || subPage >8) return;
|
if (subPage <1 || subPage >8) return;
|
||||||
|
|
||||||
if (subPage == 1) {
|
if (subPage == 1)
|
||||||
|
{
|
||||||
sappends('s',SET_F("CS"),clientSSID);
|
sappends('s',SET_F("CS"),clientSSID);
|
||||||
|
|
||||||
byte l = strlen(clientPass);
|
byte l = strlen(clientPass);
|
||||||
@ -264,50 +304,72 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 2) {
|
if (subPage == 2)
|
||||||
|
{
|
||||||
char nS[8];
|
char nS[8];
|
||||||
|
|
||||||
// add reserved and usermod pins as d.um_p array
|
// add reserved and usermod pins as d.um_p array
|
||||||
|
oappend(SET_F("d.um_p=[6,7,8,9,10,11"));
|
||||||
|
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
||||||
JsonObject mods = doc.createNestedObject(F("um"));
|
JsonObject mods = doc.createNestedObject(F("um"));
|
||||||
usermods.addToConfig(mods);
|
usermods.addToConfig(mods);
|
||||||
oappend(SET_F("d.um_p=["));
|
if (!mods.isNull()) fillUMPins(mods);
|
||||||
if (!mods.isNull()) {
|
|
||||||
uint8_t i=0;
|
#ifdef WLED_ENABLE_DMX
|
||||||
for (JsonPair kv : mods) {
|
oappend(SET_F(",2")); // DMX hardcoded pin
|
||||||
if (!kv.value().isNull()) {
|
#endif
|
||||||
// element is an JsonObject
|
|
||||||
JsonObject obj = kv.value();
|
#ifdef WLED_ENABLE_ADALIGHT
|
||||||
if (obj["pin"] != nullptr) {
|
// inform settings page that pin 3 is used by ADALights if not aleready used by strip (previous setup)
|
||||||
if (obj["pin"].is<JsonArray>()) {
|
// NOTE: this will prohibit pin 3 use on new installs
|
||||||
JsonArray pins = obj["pin"].as<JsonArray>();
|
{
|
||||||
for (JsonVariant pv : pins) {
|
bool pin3used = false;
|
||||||
if (i++) oappend(SET_F(","));
|
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||||
oappendi(pv.as<int>());
|
Bus* bus = busses.getBus(s);
|
||||||
}
|
uint8_t pins[5];
|
||||||
} else {
|
uint8_t nPins = bus->getPins(pins);
|
||||||
if (i++) oappend(SET_F(","));
|
for (uint8_t i = 0; i < nPins; i++) {
|
||||||
oappendi(obj["pin"].as<int>());
|
if (pins[i] == 3) {
|
||||||
}
|
pin3used = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (pin3used) break;
|
||||||
}
|
}
|
||||||
if (i) oappend(SET_F(","));
|
if (!pin3used && pinManager.isPinAllocated(3)) oappend(SET_F(",3")); // ADALight (RX) pin
|
||||||
oappend(SET_F("6,7,8,9,10,11")); // flash memory pins
|
|
||||||
#ifdef WLED_ENABLE_DMX
|
|
||||||
oappend(SET_F(",2")); // DMX hardcoded pin
|
|
||||||
#endif
|
|
||||||
//Adalight / Serial in requires pin 3 to be unused. However, Serial input can not be prevented by WLED
|
|
||||||
#ifdef WLED_DEBUG
|
|
||||||
oappend(SET_F(",1")); // debug output (TX) pin
|
|
||||||
#endif
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
|
||||||
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM
|
|
||||||
#endif
|
|
||||||
//TODO: add reservations for Ethernet shield pins
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
|
oappend(SET_F(",1")); // debug output (TX) pin
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||||
|
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WLED_USE_ETHERNET
|
||||||
|
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||||
|
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { oappend(","); oappend(itoa(esp32_nonconfigurable_ethernet_pins[p].pin,nS,10)); }
|
||||||
|
if (ethernetBoards[ethernetType].eth_power>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); }
|
||||||
|
if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); }
|
||||||
|
if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); }
|
||||||
|
switch (ethernetBoards[ethernetType].eth_clk_mode) {
|
||||||
|
case ETH_CLOCK_GPIO0_IN:
|
||||||
|
case ETH_CLOCK_GPIO0_OUT:
|
||||||
|
oappend(SET_F(",0"));
|
||||||
|
break;
|
||||||
|
case ETH_CLOCK_GPIO16_OUT:
|
||||||
|
oappend(SET_F(",16"));
|
||||||
|
break;
|
||||||
|
case ETH_CLOCK_GPIO17_OUT:
|
||||||
|
oappend(SET_F(",17"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
oappend(SET_F("];"));
|
oappend(SET_F("];"));
|
||||||
|
|
||||||
// set limits
|
// set limits
|
||||||
@ -317,10 +379,6 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
oappend(itoa(MAX_LED_MEMORY,nS,10));
|
oappend(itoa(MAX_LED_MEMORY,nS,10));
|
||||||
oappend(SET_F(");"));
|
oappend(SET_F(");"));
|
||||||
|
|
||||||
oappend(SET_F("d.Sf.LC.max=")); //TODO Formula for max LEDs on ESP8266 depending on types. 500 DMA or 1500 UART (about 4kB mem usage)
|
|
||||||
oappendi(MAX_LEDS);
|
|
||||||
oappend(";");
|
|
||||||
|
|
||||||
sappend('v',SET_F("LC"),ledCount);
|
sappend('v',SET_F("LC"),ledCount);
|
||||||
sappend('c',SET_F("MS"),autoSegments);
|
sappend('c',SET_F("MS"),autoSegments);
|
||||||
|
|
||||||
@ -333,19 +391,21 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
|
char 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 cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
|
||||||
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
|
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
|
||||||
|
// char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||||
oappend(SET_F("addLEDs(1);"));
|
oappend(SET_F("addLEDs(1);"));
|
||||||
uint8_t pins[5];
|
uint8_t pins[5];
|
||||||
uint8_t nPins = bus->getPins(pins);
|
uint8_t nPins = bus->getPins(pins);
|
||||||
for (uint8_t i = 0; i < nPins; i++) {
|
for (uint8_t i = 0; i < nPins; i++) {
|
||||||
lp[1] = 48+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',lt,bus->getType());
|
||||||
sappend('v',co,bus->getColorOrder());
|
sappend('v',co,bus->getColorOrder());
|
||||||
sappend('v',ls,bus->getStart());
|
sappend('v',ls,bus->getStart());
|
||||||
sappend('c',cv,bus->reversed);
|
sappend('c',cv,bus->reversed);
|
||||||
sappend('c',sl,bus->skippedLeds());
|
sappend('c',sl,bus->skippedLeds());
|
||||||
|
// sappend('c',ew,bus->isRgbw());
|
||||||
}
|
}
|
||||||
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
|
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
|
||||||
sappend('v',SET_F("LA"),strip.milliampsPerLed);
|
sappend('v',SET_F("LA"),strip.milliampsPerLed);
|
||||||
@ -391,6 +451,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
{
|
{
|
||||||
sappends('s',SET_F("DS"),serverDescription);
|
sappends('s',SET_F("DS"),serverDescription);
|
||||||
sappend('c',SET_F("ST"),syncToggleReceive);
|
sappend('c',SET_F("ST"),syncToggleReceive);
|
||||||
|
sappend('c',SET_F("SU"),simplifiedUI);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 4)
|
if (subPage == 4)
|
||||||
|
Loading…
Reference in New Issue
Block a user