Merge remote-tracking branch 'origin/master' into codegen-html

This commit is contained in:
Ruslan Gainutdinov 2020-06-08 19:43:03 +03:00
commit 00f00b8198
44 changed files with 2732 additions and 1326 deletions

Binary file not shown.

View File

@ -2,6 +2,33 @@
### Development versions after 0.10.0 release ### Development versions after 0.10.0 release
#### Build 2006060
- Added five effects by Andrew Tuline (Phased, Phased Noise, Sine, Noise Pal and Twinkleup)
- Added two new effects by Aircoookie (Sunrise and Flow)
- Added US-style sequence to traffic light effect
- Merged pull request #964 adding 9 key IR remote
#### Build 2005280
- Added v2 usermod API
- Added v2 example usermod `usermod_v2_example` in the usermods folder as prelimary documentation
- Added DS18B20 Temperature usermod with Info page support
- Disabled MQTT on ESP01 build to make room in flash
#### Build 2005230
- Fixed TPM2
#### Build 2005220
- Added TPM2.NET protocol support (need to set WLED broadcast UDP port to 65506)
- Added TPM2 protocol support via Serial
- Support up to 6553 seconds preset cycle durations (backend, NOT yet in UI)
- Merged pull request #591 fixing WS2801 color order
- Merged pull request #858 adding fully featured travis builds
- Merged pull request #862 adding DMX proxy feature
#### Build 2005100 #### Build 2005100
- Update to Espalexa v2.4.6 (+1.6kB free heap memory) - Update to Espalexa v2.4.6 (+1.6kB free heap memory)

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -74,6 +74,8 @@ arduino_core_develop = https://github.com/platformio/platform-espressif8266#deve
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
# Platform to use for ESP8266 # Platform to use for ESP8266
platform_wled_default = ${common.arduino_core_2_7_1}
# We use 2.7.0+ on analog boards because of PWM flicker fix
platform_latest = ${common.arduino_core_2_7_1} platform_latest = ${common.arduino_core_2_7_1}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -165,6 +167,8 @@ lib_deps =
AsyncTCP@1.0.3 AsyncTCP@1.0.3
Esp Async WebServer@1.2.0 Esp Async WebServer@1.2.0
IRremoteESP8266@2.7.3 IRremoteESP8266@2.7.3
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
#TFT_eSPI
#For use SSD1306 OLED display uncomment following #For use SSD1306 OLED display uncomment following
#U8g2@~2.27.2 #U8g2@~2.27.2
#For Dallas sensor uncomment following 2 lines #For Dallas sensor uncomment following 2 lines
@ -180,51 +184,51 @@ lib_ignore =
[env:nodemcuv2] [env:nodemcuv2]
board = nodemcuv2 board = nodemcuv2
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m} board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} build_flags = ${common.build_flags_esp8266}
[env:esp01] [env:esp01]
board = esp01 board = esp01
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_512k} board_build.ldscript = ${common.ldscript_512k}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT
[env:esp01_1m_ota] [env:esp01_1m_ota]
board = esp01_1m board = esp01_1m
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_1m0m} board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT
[env:esp01_1m_full] [env:esp01_1m_full]
board = esp01_1m board = esp01_1m
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_1m0m} board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA
[env:esp07] [env:esp07]
board = esp07 board = esp07
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m} board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} build_flags = ${common.build_flags_esp8266}
[env:d1_mini] [env:d1_mini]
board = d1_mini board = d1_mini
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
upload_speed = 921500 upload_speed = 921600
board_build.ldscript = ${common.ldscript_4m1m} board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} build_flags = ${common.build_flags_esp8266}
[env:heltec_wifi_kit_8] [env:heltec_wifi_kit_8]
board = d1_mini board = d1_mini
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m} board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} build_flags = ${common.build_flags_esp8266}
[env:h803wf] [env:h803wf]
board = d1_mini board = d1_mini
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m} board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} -D LEDPIN=1 -D WLED_DISABLE_INFRARED build_flags = ${common.build_flags_esp8266} -D LEDPIN=1 -D WLED_DISABLE_INFRARED
@ -267,7 +271,7 @@ build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_
[env:d1_mini_debug] [env:d1_mini_debug]
board = d1_mini board = d1_mini
build_type = debug build_type = debug
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m} board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} ${common.debug_flags} build_flags = ${common.build_flags_esp8266} ${common.debug_flags}
@ -276,7 +280,7 @@ board = d1_mini
upload_protocol = espota upload_protocol = espota
# exchange for your WLED IP # exchange for your WLED IP
upload_port = "10.10.1.27" upload_port = "10.10.1.27"
platform = ${common.platform_latest} platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m} board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} build_flags = ${common.build_flags_esp8266}

View File

@ -1,16 +1,17 @@
![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/master/wled_logo.png) <p align="center">
<img src="/images/wled_logo.png">
<a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a>
<a href="https://wled.discourse.group"><img src="https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square"></a>
<a href="https://discord.gg/KuqP7NE"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
<a href="https://github.com/Aircoookie/WLED/wiki"><img src="https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square"></a>
<a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a>
</p>
# 👋 Welcome to my project WLED!
[![](https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square)](https://github.com/Aircoookie/WLED/releases) A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs or also SPI based chipsets like the WS2801!
[![](https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square)](https://wled.discourse.group)
[![](https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square)](https://discord.gg/KuqP7NE)
[![](https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square)](https://github.com/Aircoookie/WLED/wiki)
[![](https://img.shields.io/badge/app-wled-blue.svg?style=flat-square)](https://github.com/Aircoookie/WLED-App)
## Welcome to my project WLED! ## ⚙️ Features
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs!
### Features:
- WS2812FX library integrated for over 100 special effects - WS2812FX library integrated for over 100 special effects
- FastLED noise effects and 50 palettes - FastLED noise effects and 50 palettes
- Modern UI with color, effect and segment controls - Modern UI with color, effect and segment controls
@ -25,7 +26,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
- Configurable analog clock + support for the Cronixie kit by Diamex - Configurable analog clock + support for the Cronixie kit by Diamex
- Configurable Auto Brightness limit for safer operation - Configurable Auto Brightness limit for safer operation
### Supported light control interfaces: ## 💡 Supported light control interfaces
- WLED app for Android and iOS - WLED app for Android and iOS
- JSON and HTTP request APIs - JSON and HTTP request APIs
- MQTT - MQTT
@ -40,7 +41,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
- Infrared remotes (24-key RGB, receiver required) - Infrared remotes (24-key RGB, receiver required)
- Simple timers/schedules (time from NTP, timezones/DST supported) - Simple timers/schedules (time from NTP, timezones/DST supported)
### Quick start guide and documentation: ## 📲 Quick start guide and documentation
See the [wiki](https://github.com/Aircoookie/WLED/wiki)! See the [wiki](https://github.com/Aircoookie/WLED/wiki)!
@ -54,18 +55,39 @@ Russian speakers, check out the videos by Room31:
[WLED Firmware Overview: Interface and Settings](https://youtu.be/h7lKsczEI7E) [WLED Firmware Overview: Interface and Settings](https://youtu.be/h7lKsczEI7E)
[ESP8266 based LED controller for WS2812b strip. WLED Firmware + OpenHAB](https://youtu.be/K4ioTt3XvGc) [ESP8266 based LED controller for WS2812b strip. WLED Firmware + OpenHAB](https://youtu.be/K4ioTt3XvGc)
### Other ## 🖼️ Images
<img src="/images/macbook-pro-space-gray-on-the-wooden-table.webp" width="50%"><img src="/images/walking-with-iphone-x.webp" width="50%">
## 💾 Compatible LED Strips
Type | Voltage | Comments
|---|---|---|
WS2812B | 5v |
WS2813 | 5v |
SK6812 | 5v | RGBW
APA102 | 5v | C/D
WS2801 | 5v | C/D
LPD8806 | 5v | C/D
TM1814 | 12v | RGBW
WS2811 | 12v | 3-LED segments
WS2815 | 12v |
GS8208 | 12v |
## ✌️ Other
Licensed under the MIT license Licensed under the MIT license
Credits [here](https://github.com/Aircoookie/WLED/wiki/Contributors-&-About)! Credits [here](https://github.com/Aircoookie/WLED/wiki/Contributors-&-About)!
Uses Linearicons by Perxis! Uses Linearicons by Perxis!
Join the Discord [server](https://discord.gg/KuqP7NE) to discuss everything about WLED! Join the Discord server to discuss everything about WLED!
[![WLED Discord](https://discordapp.com/api/guilds/473448917040758787/widget.png?style=banner2)](https://discord.gg/KuqP7NE)
Check out the WLED [Discourse forum](https://wled.discourse.group)! Check out the WLED [Discourse forum](https://wled.discourse.group)!
You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com), but please only do so if you want to talk to me privately. You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com), but please only do so if you want to talk to me privately.
If WLED really brightens up your every day, you can [![](https://img.shields.io/badge/send%20me%20a%20small%20gift-paypal-blue.svg?style=flat-square)](https://paypal.me/aircoookie) If WLED really brightens up your every day, you can [![](https://img.shields.io/badge/send%20me%20a%20small%20gift-paypal-blue.svg?style=flat-square)](https://paypal.me/aircoookie)
*Disclaimer:* *Disclaimer:*
If you are sensitive to photoeleptic seizures it is not recommended that you use this software. If you are sensitive to photoeleptic seizures it is not recommended that you use this software.
In case you still want to try, don't use strobe, lighting or noise modes or high effect speed settings. In case you still want to try, don't use strobe, lighting or noise modes or high effect speed settings.

View File

@ -0,0 +1,10 @@
# Usermods API v2 example usermod
In this usermod file you can find the documentation on how to take advantage of the new version 2 usermods!
## Installation
Copy `usermod_v2_example.h` to the wled00 directory.
Uncomment the corresponding lines in `usermods_list.h` and compile!
_(You shouldn't need to actually install this, it does nothing useful)_

View File

@ -0,0 +1,119 @@
#pragma once
#include "wled.h"
/*
* Usermods allow you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
*
* This is an example for a v2 usermod.
* 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.
*
* 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.
* Please remember to rename the class and file to a descriptive name.
* You may also use multiple .h and .cpp files.
*
* Using a usermod:
* 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
*/
//class name. Use something descriptive and leave the ": public Usermod" part :)
class MyExampleUsermod : public Usermod {
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long lastTime = 0;
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup() {
//Serial.println("Hello from my usermod!");
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected() {
//Serial.println("Connected to WiFi!");
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop() {
if (millis() - lastTime > 1000) {
//Serial.println("I'm alive!");
lastTime = millis();
}
}
/*
* 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.
* Below it is shown how this could be used for e.g. a light sensor
*/
/*
void addToJsonInfo(JsonObject& root)
{
int reading = 20;
//this code adds "u":{"Light":[20," lux"]} to the info object
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray lightArr = user.createNestedArray("Light"); //name
lightArr.add(reading); //value
lightArr.add(" lux"); //unit
}
*/
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root)
{
//root["user0"] = userVar0;
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root)
{
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!"));
}
/*
* 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.
*/
uint16_t getId()
{
return USERMOD_ID_EXAMPLE;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

View File

@ -0,0 +1,17 @@
# Fix unreachable Webserver
This modification performs a ping request to the local IP address every 60 seconds. By this procedure the web server remains accessible in some problematic WLAN environments.
The modification works with static or DHCP IP address configuration
_Story:_
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
## Installation
Copy and replace the file `usermod.cpp` in wled00 directory.

View File

@ -0,0 +1,43 @@
#include "wled.h"
/*
* This file allows you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* bytes 2400+ are currently ununsed, but might be used for future wled features
*/
#include <ping.h>
const int PingDelayMs = 60000;
long lastCheckTime = 0;
bool connectedWiFi = false;
ping_option pingOpt;
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup()
{
}
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
void userConnected()
{
connectedWiFi = true;
// initialize ping_options structure
memset(&pingOpt, 0, sizeof(struct ping_option));
pingOpt.count = 1;
pingOpt.ip = WiFi.localIP();
}
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
void userLoop()
{
if (connectedWiFi && millis()-lastCheckTime > PingDelayMs)
{
ping_start(&pingOpt);
lastCheckTime = millis();
}
}

View File

@ -0,0 +1,77 @@
# TTGO T-Display ESP32 with 240x135 TFT via SPI with TFT_eSPI
This usermod allows use of the TTGO T-Display ESP32 module with integrated 240x135 display
for controlling WLED and showing the following information:
* Current SSID
* IP address if obtained
* in AP mode and turned off lightning AP password is shown
* Current effect
* Current palette
Usermod based on a rework of the ssd1306_i2c_oled_u8g2 usermod from the WLED repo.
## Hardware
![Hardware](assets/ttgo_hardware1.png)
## Github reference for TTGO-Tdisplay
* [TTGO T-Display](https://github.com/Xinyuan-LilyGO/TTGO-T-Display)
## Requirements
Functionality checked with:
* TTGO T-Display
* PlatformIO
* Group of 4 individual Neopixels from Adafruit, and a full string of 68 LEDs.
## Platformio Requirements
### Platformio.ini changes
Under the root folder of the project, in the `platformio.ini` file, uncomment the `TFT_eSPI` line within the [common] section, under `lib_deps`:
```ini
# platformio.ini
...
[common]
...
lib_deps =
...
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
#TFT_eSPI
...
```
Also, while in the `platformio.ini` file, you must change the environment setup to build for just the esp32dev platform as follows:
Comment out the line described below:
```ini
# Travis CI binaries (comment this out when building for single board)
; default_envs = travis_esp8266, esp01, esp01_1m_ota, travis_esp32
```
and UNCOMMENT the following line in the 'Single binaries' section:
```ini
default_envs = esp32dev
```
Save the `platformio.ini` file. Once this is saved, the required library files should be automatically downloaded for modifications in a later step.
### Platformio_overrides.ini (added)
Copy the `platformio_overrides.ini` file which is contained in the `usermods/TTGO-T-Display/` folder into the root of your project folder. This file contains an override that remaps the button pin of WLED to use the on-board button to the right of the USB-C connector (when viewed with the port oriented downward - see hardware photo).
### TFT_eSPI Library Adjustments (board selection)
We need to modify a file in the `TFT_eSPI` library to select the correct board. 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_ID1559` folder.
Modify the `User_Setup_Select.h` file as follows:
* Comment out the following line (which is the 'default' setup file):
```ini
//#include <User_Setup.h> // Default setup is root library folder
```
* Uncomment the following line (which points to the setup file for the TTGO T-Display):
```ini
#include <User_Setups/Setup25_TTGO_T_Display.h> // Setup file for ESP32 and TTGO T-Display ST7789V SPI bus TFT
```
Run the build and it should complete correctly. If you see a failure like this:
```ini
xtensa-esp32-elf-g++: error: wled00\wled00.ino.cpp: No such file or directory
xtensa-esp32-elf-g++: fatal error: no input files
```
Just try building again - I find that sometimes this happens on the first build attempt and subsequent attempts will build correctly.
## Arduino IDE
- UNTESTED

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 KiB

View File

@ -0,0 +1,8 @@
[env:esp32dev]
build_flags = ${common.build_flags_esp32}
; PIN defines - uncomment and change, if needed:
; -D LEDPIN=2
-D BTNPIN=35
; -D IR_PIN=4
; -D RLYPIN=12
; -D RLYMDE=1

View File

@ -0,0 +1,214 @@
/*
* This file allows you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* bytes 2400+ are currently ununsed, but might be used for future wled features
*/
/*
* Pin 2 of the TTGO T-Display serves as the data line for the LED string.
* Pin 35 is set up as the button pin in the platformio_overrides.ini file.
* The button can be set up via the macros section in the web interface.
* I use the button to cycle between presets.
* The Pin 35 button is the one on the RIGHT side of the USB-C port on the board,
* when the port is oriented downwards. See readme.md file for photo.
* The display is set up to turn off after 5 minutes, and turns on automatically
* when a change in the dipslayed info is detected (within a 5 second interval).
*/
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
#include "wled.h"
#include <TFT_eSPI.h>
#include <SPI.h>
#include "WiFi.h"
#include <Wire.h>
#ifndef TFT_DISPOFF
#define TFT_DISPOFF 0x28
#endif
#ifndef TFT_SLPIN
#define TFT_SLPIN 0x10
#endif
#define TFT_MOSI 19
#define TFT_SCLK 18
#define TFT_CS 5
#define TFT_DC 16
#define TFT_RST 23
#define TFT_BL 4 // Display backlight control pin
#define ADC_EN 14 // Used for enabling battery voltage measurements - not used in this program
TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke custom library
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup() {
Serial.begin(115200);
Serial.println("Start");
tft.init();
tft.setRotation(3); //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.setTextSize(2);
tft.setTextColor(TFT_WHITE);
tft.setCursor(1, 10);
tft.setTextDatum(MC_DATUM);
tft.setTextSize(2);
tft.print("Loading...");
if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
}
// tft.setRotation(3);
}
// 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;
uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2
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 5 minutes with no change.
if(!displayTurnedOff && millis() - lastRedraw > 5*60*1000) {
digitalWrite(TFT_BL, LOW); // Turn backlight off.
displayTurnedOff = true;
}
// Check if values which are shown on display changed from the last time.
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
needRedraw = true;
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
needRedraw = true;
} else if (knownBrightness != bri) {
needRedraw = true;
} else if (knownMode != strip.getMode()) {
needRedraw = true;
} else if (knownPalette != strip.getSegment(0).palette) {
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.setCursor(1, 10);
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 IP or Psssword
tft.setCursor(1, 40);
// Print password in AP mode and if led is OFF.
if (apActive && bri == 0)
tft.print(apPass);
else
tft.print(knownIp);
// Third row with mode name
tft.setCursor(1, 70);
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;
}
// Fourth row with palette name
tft.setCursor(1, 100);
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;
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;
}
}

View File

@ -0,0 +1,40 @@
# Temperature usermod
Based on the excellent `QuinLED_Dig_Uno_Temp_MQTT` by srg74!
This usermod will read from an attached DS18B20 temperature sensor (as available on the QuinLED Dig-Uno)
The temperature is displayed both in the Info section of the web UI as well as published to the `/temperature` MQTT topic if enabled.
This usermod will be expanded with support for different sensor types in the future.
## Installation
Copy `usermod_temperature.h` to the wled00 directory.
Uncomment the corresponding lines in `usermods_list.h` and compile!
If this is the only v2 usermod you plan to use, you can alternatively replace `usermods_list.h` in wled00 with the one in this folder.
## Project link
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
### PlatformIO requirements
You might have to 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
...
```

View File

@ -0,0 +1,79 @@
#pragma once
#include "wled.h"
#include <DallasTemperature.h> //DS18B20
//Pin defaults for QuinLed Dig-Uno
#ifdef ARDUINO_ARCH_ESP32
#define TEMPERATURE_PIN 18
#else //ESP8266 boards
#define TEMPERATURE_PIN 14
#endif
#define TEMP_CELSIUS // Comment out for Fahrenheit
#define MEASUREMENT_INTERVAL 60000 //1 Minute
OneWire oneWire(TEMPERATURE_PIN);
DallasTemperature sensor(&oneWire);
class UsermodTemperature : public Usermod {
private:
//set last reading as "40 sec before boot", so first reading is taken after 20 sec
unsigned long lastMeasurement = UINT32_MAX - 40000;
float temperature = 0.0f;
public:
void getReading() {
sensor.requestTemperatures();
#ifdef TEMP_CELSIUS
temperature = sensor.getTempCByIndex(0);
#else
temperature = sensor.getTempFByIndex(0);
#endif
}
void setup() {
sensor.begin();
sensor.setResolution(9);
}
void loop() {
if (millis() - lastMeasurement > MEASUREMENT_INTERVAL)
{
getReading();
if (WLED_MQTT_CONNECTED) {
char subuf[38];
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, "/temperature");
mqtt->publish(subuf, 0, true, String(temperature).c_str());
}
lastMeasurement = millis();
}
}
void addToJsonInfo(JsonObject& root) {
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray temp = user.createNestedArray("Temperature");
if (temperature == DEVICE_DISCONNECTED_C) {
temp.add(0);
temp.add(" Sensor Error!");
return;
}
temp.add(temperature);
#ifdef TEMP_CELSIUS
temp.add("°C");
#else
temp.add("°F");
#endif
}
uint16_t getId()
{
return USERMOD_ID_TEMPERATURE;
}
};

View File

@ -0,0 +1,25 @@
#include "wled.h"
/*
* Register your v2 usermods here!
*/
/*
* Add/uncomment your usermod filename here (and once more below)
* || || ||
* \/ \/ \/
*/
//#include "usermod_v2_example.h"
#include "usermod_temperature.h"
//#include "usermod_v2_empty.h"
void registerUsermods()
{
/*
* Add your usermod class name here
* || || ||
* \/ \/ \/
*/
//usermods.add(new MyExampleUsermod());
usermods.add(new UsermodTemperature());
//usermods.add(new UsermodRenameMe());
}

View File

@ -7,7 +7,7 @@ If you have created an usermod that you believe is useful (for example to suppor
In order for other people to be able to have fun with your usermod, please keep these points in mind: In order for other people to be able to have fun with your usermod, please keep these points in mind:
- Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`) - Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`)
- Include your custom `usermod.cpp` file - Include your custom files
- If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one has to take to use the usermod - If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one has to take to use the usermod
- Create a pull request! - Create a pull request!
- If your feature is useful for the majority of WLED users, I will consider adding it to the base code! - If your feature is useful for the majority of WLED users, I will consider adding it to the base code!
@ -15,4 +15,7 @@ In order for other people to be able to have fun with your usermod, please keep
While I do my best to not break too much, keep in mind that as WLED is being updated, usermods might break. While I do my best to not break too much, keep in mind that as WLED is being updated, usermods might break.
I am not actively maintaining any usermod in this directory, that is your responsibility as the creator of the usermod. I am not actively maintaining any usermod in this directory, that is your responsibility as the creator of the usermod.
For new usermods, I would recommend trying out the new v2 usermod API, which allows installing multiple usermods at once and new functions!
You can take a look at `EXAMPLE_v2` for some documentation and at `Temperature` for a completed v2 usermod!
Thank you for your help :) Thank you for your help :)

View File

@ -0,0 +1,211 @@
#pragma once
#include "wled.h"
//v2 usermod that allows to change brightness and color using a rotary encoder,
//change between modes by pressing a button (many encoder have one included)
class RotaryEncoderSet : public Usermod
{
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long lastTime = 0;
/*
** Rotary Encoder Example
** Use the Sparkfun Rotary Encoder to vary brightness of LED
**
** Sample the encoder at 500Hz using the millis() function
*/
int fadeAmount = 5; // how many points to fade the Neopixel with each step
unsigned long currentTime;
unsigned long loopTime;
const int pinA = 5; // DT from encoder
const int pinB = 18; // CLK from encoder
const int pinC = 23; // SW from encoder
unsigned char select_state = 0; // 0 = brightness 1 = color
unsigned char button_state = HIGH;
unsigned char prev_button_state = HIGH;
CRGB fastled_col;
CHSV prim_hsv;
int16_t new_val;
unsigned char Enc_A;
unsigned char Enc_B;
unsigned char Enc_A_prev = 0;
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup()
{
//Serial.println("Hello from my usermod!");
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
pinMode(pinC, INPUT_PULLUP);
currentTime = millis();
loopTime = currentTime;
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected()
{
//Serial.println("Connected to WiFi!");
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop()
{
currentTime = millis(); // get the current elapsed time
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
{
button_state = digitalRead(pinC);
if (prev_button_state != button_state)
{
if (button_state == LOW)
{
if (select_state == 1)
{
select_state = 0;
}
else
{
select_state = 1;
}
prev_button_state = button_state;
}
else
{
prev_button_state = button_state;
}
}
int Enc_A = digitalRead(pinA); // Read encoder pins
int Enc_B = digitalRead(pinB);
if ((!Enc_A) && (Enc_A_prev))
{ // A has gone from high to low
if (Enc_B == HIGH)
{ // B is high so clockwise
if (select_state == 0)
{
if (bri + fadeAmount <= 255)
bri += fadeAmount; // increase the brightness, dont go over 255
}
else
{
fastled_col.red = col[0];
fastled_col.green = col[1];
fastled_col.blue = col[2];
prim_hsv = rgb2hsv_approximate(fastled_col);
new_val = (int16_t)prim_hsv.h + fadeAmount;
if (new_val > 255)
new_val -= 255; // roll-over if bigger than 255
if (new_val < 0)
new_val += 255; // roll-over if smaller than 0
prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col);
col[0] = fastled_col.red;
col[1] = fastled_col.green;
col[2] = fastled_col.blue;
}
}
else if (Enc_B == LOW)
{ // B is low so counter-clockwise
if (select_state == 0)
{
if (bri - fadeAmount >= 0)
bri -= fadeAmount; // decrease the brightness, dont go below 0
}
else
{
fastled_col.red = col[0];
fastled_col.green = col[1];
fastled_col.blue = col[2];
prim_hsv = rgb2hsv_approximate(fastled_col);
new_val = (int16_t)prim_hsv.h - fadeAmount;
if (new_val > 255)
new_val -= 255; // roll-over if bigger than 255
if (new_val < 0)
new_val += 255; // roll-over if smaller than 0
prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col);
col[0] = fastled_col.red;
col[1] = fastled_col.green;
col[2] = fastled_col.blue;
}
}
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
updateInterfaces()
}
Enc_A_prev = Enc_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
}
/*
* 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.
* Below it is shown how this could be used for e.g. a light sensor
*/
/*
void addToJsonInfo(JsonObject& root)
{
int reading = 20;
//this code adds "u":{"Light":[20," lux"]} to the info object
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray lightArr = user.createNestedArray("Light"); //name
lightArr.add(reading); //value
lightArr.add(" lux"); //unit
}
*/
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject &root)
{
//root["user0"] = userVar0;
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject &root)
{
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!"));
}
/*
* 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.
*/
uint16_t getId()
{
return 0xABCD;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

View File

@ -869,6 +869,7 @@ uint16_t WS2812FX::mode_traffic_light(void) {
if (now - SEGENV.step > mdelay) if (now - SEGENV.step > mdelay)
{ {
SEGENV.aux0++; SEGENV.aux0++;
if (SEGENV.aux0 == 1 && SEGMENT.intensity > 140) SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence
if (SEGENV.aux0 > 3) SEGENV.aux0 = 0; if (SEGENV.aux0 > 3) SEGENV.aux0 = 0;
SEGENV.step = now; SEGENV.step = now;
} }
@ -3334,3 +3335,208 @@ uint16_t WS2812FX::mode_solid_glitter()
} }
return FRAMETIME; return FRAMETIME;
} }
/*
* Mode simulates a gradual sunrise
*/
uint16_t WS2812FX::mode_sunrise() {
//speed 0 - static sun
//speed 1 - 120: sunrise time in minutes
//speed 121 - 240 : sunset time in minutes - 120;
//speed above: "breathing" rise and set
if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) {
SEGENV.step = millis(); //save starting time, millis() because now can change from sync
SEGENV.aux0 = SEGMENT.speed;
}
fill(0);
uint16_t stage = 0xFFFF;
uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds
if (SEGMENT.speed > 120) { //quick sunrise and sunset
uint16_t counter = (now >> 1) * (((SEGMENT.speed -120) >> 1) +1);
stage = triwave16(counter);
} else if (SEGMENT.speed) { //sunrise
uint8_t durMins = SEGMENT.speed;
if (durMins > 60) durMins -= 60;
uint32_t s10Target = durMins * 600;
if (s10SinceStart > s10Target) s10SinceStart = s10Target;
stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF);
if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset
}
for (uint16_t i = 0; i <= SEGLEN/2; i++)
{
//default palette is Fire
uint32_t c = color_from_palette(0, false, true, 255); //background
uint16_t wave = triwave16((i * stage) / SEGLEN);
wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15);
if (wave > 240) { //clipped, full white sun
c = color_from_palette( 240, false, true, 255);
} else { //transition
c = color_from_palette(wave, false, true, 255);
}
setPixelColor(i, c);
setPixelColor(SEGLEN - i - 1, c);
}
return FRAMETIME;
}
/*
* Effects by Andrew Tuline
*/
uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline.
uint8_t allfreq = 16; // Base frequency.
//float* phasePtr = reinterpret_cast<float*>(SEGENV.step); // Phase change value gets calculated.
static float phase = 0;//phasePtr[0];
uint8_t cutOff = (255-SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192).
uint8_t modVal = 5;//SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5).
uint8_t index = now/64; // Set color rotation speed
phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4)
//phasePtr[0] = phase;
for (int i = 0; i < SEGLEN; i++) {
if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise.
uint16_t val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that leds[0] is used.
if (modVal == 0) modVal = 1;
val += phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline.
uint8_t b = cubicwave8(val); // Now we make an 8 bit sinewave.
b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, false, 0), b));
index += 256 / SEGLEN;
}
return FRAMETIME;
}
uint16_t WS2812FX::mode_phased(void) {
return phased_base(0);
}
uint16_t WS2812FX::mode_phased_noise(void) {
return phased_base(1);
}
uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
for (int i = 0; i<SEGLEN; i++) {
uint8_t ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work.
uint8_t pixBri = sin8(ranstart + 16 * now/(256-SEGMENT.speed));
if (random8() > SEGMENT.intensity) pixBri = 0;
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i*20, false, PALETTE_SOLID_WRAP, 0), pixBri));
}
return FRAMETIME;
}
// Peaceful noise that's slow and with gradually changing palettes. Does not support WLED palettes or default colours or controls.
uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by Andrew Tuline.
uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
//#define scale 30
uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGBPalette16* palettes = reinterpret_cast<CRGBPalette16*>(SEGENV.data);
uint16_t changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec
if (millis() - SEGENV.step > changePaletteMs)
{
SEGENV.step = millis();
uint8_t baseI = random8();
palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255)));
}
CRGB color;
//EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms)
nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations.
if (SEGMENT.palette > 0) palettes[0] = currentPalette;
for(int i = 0; i < SEGLEN; i++) {
uint8_t index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis.
color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette.
setPixelColor(i, color.red, color.green, color.blue);
}
SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave.
return FRAMETIME;
}
// Sine waves that have controllable phase change speed, frequency and cutoff. By Andrew Tuline.
// SEGMENT.speed ->Speed, SEGMENT.intensity -> Frequency (SEGMENT.fft1 -> Color change, SEGMENT.fft2 -> PWM cutoff)
//
uint16_t WS2812FX::mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline
//#define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0
uint16_t colorIndex = now /32;//(256 - SEGMENT.fft1); // Amount of colour change.
SEGENV.step += SEGMENT.speed/16; // Speed of animation.
uint16_t freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal.
for (int i=0; i<SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows:
int pixBri = cubicwave8((i*freq)+SEGENV.step);//qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub)..
//setPixCol(i, i*colorIndex/255, pixBri);
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri));
}
return FRAMETIME;
}
/*
* Best of both worlds from Palette and Spot effects. By Aircoookie
*/
uint16_t WS2812FX::mode_flow(void)
{
uint16_t counter = 0;
if (SEGMENT.speed != 0)
{
counter = now * ((SEGMENT.speed >> 2) +1);
counter = counter >> 8;
}
uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs
uint16_t zones = (SEGMENT.intensity * maxZones) >> 8;
if (zones & 0x01) zones++; //zones must be even
if (zones < 2) zones = 2;
uint16_t zoneLen = SEGLEN / zones;
uint16_t offset = (SEGLEN - zones * zoneLen) >> 1;
fill(color_from_palette(-counter, false, true, 255));
for (uint16_t z = 0; z < zones; z++)
{
uint16_t pos = offset + z * zoneLen;
for (uint16_t i = 0; i < zoneLen; i++)
{
uint8_t colorIndex = (i * 255 / zoneLen) - counter;
uint16_t led = (z & 0x01) ? i : (zoneLen -1) -i;
if (IS_REVERSE) led = (zoneLen -1) -led;
setPixelColor(pos + led, color_from_palette(colorIndex, false, true, 255));
}
}
return FRAMETIME;
}

View File

@ -98,7 +98,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE ) #define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED ) #define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
#define MODE_COUNT 104 #define MODE_COUNT 111
#define FX_MODE_STATIC 0 #define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1 #define FX_MODE_BLINK 1
@ -204,6 +204,13 @@
#define FX_MODE_PACIFICA 101 #define FX_MODE_PACIFICA 101
#define FX_MODE_CANDLE_MULTI 102 #define FX_MODE_CANDLE_MULTI 102
#define FX_MODE_SOLID_GLITTER 103 #define FX_MODE_SOLID_GLITTER 103
#define FX_MODE_SUNRISE 104
#define FX_MODE_PHASED 105
#define FX_MODE_TWINKLEUP 106
#define FX_MODE_NOISEPAL 107
#define FX_MODE_SINEWAVE 108
#define FX_MODE_PHASEDNOISE 109
#define FX_MODE_FLOW 110
class WS2812FX { class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void); typedef uint16_t (WS2812FX::*mode_ptr)(void);
@ -396,6 +403,13 @@ class WS2812FX {
_mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica; _mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica;
_mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi; _mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi;
_mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter; _mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter;
_mode[FX_MODE_SUNRISE] = &WS2812FX::mode_sunrise;
_mode[FX_MODE_PHASED] = &WS2812FX::mode_phased;
_mode[FX_MODE_TWINKLEUP] = &WS2812FX::mode_twinkleup;
_mode[FX_MODE_NOISEPAL] = &WS2812FX::mode_noisepal;
_mode[FX_MODE_SINEWAVE] = &WS2812FX::mode_sinewave;
_mode[FX_MODE_PHASEDNOISE] = &WS2812FX::mode_phased_noise;
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
_brightness = DEFAULT_BRIGHTNESS; _brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black); currentPalette = CRGBPalette16(CRGB::Black);
@ -461,7 +475,7 @@ class WS2812FX {
uint32_t uint32_t
timebase, timebase,
color_wheel(uint8_t), color_wheel(uint8_t),
color_from_palette(uint16_t, bool, bool, uint8_t, uint8_t pbri = 255), color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
color_blend(uint32_t,uint32_t,uint8_t), color_blend(uint32_t,uint32_t,uint8_t),
gamma32(uint32_t), gamma32(uint32_t),
getLastShow(void), getLastShow(void),
@ -583,7 +597,14 @@ class WS2812FX {
mode_heartbeat(void), mode_heartbeat(void),
mode_pacifica(void), mode_pacifica(void),
mode_candle_multi(void), mode_candle_multi(void),
mode_solid_glitter(void); mode_solid_glitter(void),
mode_sunrise(void),
mode_phased(void),
mode_twinkleup(void),
mode_noisepal(void),
mode_sinewave(void),
mode_phased_noise(void),
mode_flow(void);
private: private:
NeoPixelWrapper *bus; NeoPixelWrapper *bus;
@ -630,7 +651,8 @@ class WS2812FX {
running(uint32_t, uint32_t), running(uint32_t, uint32_t),
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),
phased_base(uint8_t);
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat); CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff); CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
@ -669,7 +691,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple", "Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst", "Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow", "Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter" "Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise","Flow"
])====="; ])=====";

View File

@ -707,26 +707,28 @@ void WS2812FX::handle_palette(void)
_segment_index_palette_last = _segment_index; _segment_index_palette_last = _segment_index;
byte paletteIndex = SEGMENT.palette; byte paletteIndex = SEGMENT.palette;
if (SEGMENT.mode == FX_MODE_GLITTER && paletteIndex == 0) paletteIndex = 11; if (paletteIndex == 0) //default palette. Differs depending on effect
{
switch (SEGMENT.mode)
{
case FX_MODE_FIRE_2012 : paletteIndex = 35; break; //heat palette
case FX_MODE_COLORWAVES : paletteIndex = 26; break; //landscape 33
case FX_MODE_FILLNOISE8 : paletteIndex = 9; break; //ocean colors
case FX_MODE_NOISE16_1 : paletteIndex = 20; break; //Drywet
case FX_MODE_NOISE16_2 : paletteIndex = 43; break; //Blue cyan yellow
case FX_MODE_NOISE16_3 : paletteIndex = 35; break; //heat palette
case FX_MODE_NOISE16_4 : paletteIndex = 26; break; //landscape 33
case FX_MODE_GLITTER : paletteIndex = 11; break; //rainbow colors
case FX_MODE_SUNRISE : paletteIndex = 35; break; //heat palette
case FX_MODE_FLOW : paletteIndex = 6; break; //party
}
}
if (SEGMENT.mode >= FX_MODE_METEOR && paletteIndex == 0) paletteIndex = 4; if (SEGMENT.mode >= FX_MODE_METEOR && paletteIndex == 0) paletteIndex = 4;
switch (paletteIndex) switch (paletteIndex)
{ {
case 0: {//default palette. Differs depending on effect case 0: //default palette. Exceptions for specific effects above
switch (SEGMENT.mode) targetPalette = PartyColors_p; break;
{
case FX_MODE_FIRE_2012 : load_gradient_palette(22); break;//heat palette
case FX_MODE_COLORWAVES : load_gradient_palette(13); break;//landscape 33
case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p; break;
case FX_MODE_NOISE16_1 : load_gradient_palette(17); break;//Drywet
case FX_MODE_NOISE16_2 : load_gradient_palette(30); break;//Blue cyan yellow
case FX_MODE_NOISE16_3 : load_gradient_palette(22); break;//heat palette
case FX_MODE_NOISE16_4 : load_gradient_palette(13); break;//landscape 33
//case FX_MODE_GLITTER : targetPalette = RainbowColors_p; break;
default: targetPalette = PartyColors_p; break;//palette, bpm
}
break;}
case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments
if (!singleSegmentMode) if (!singleSegmentMode)
{ {
@ -778,7 +780,7 @@ void WS2812FX::handle_palette(void)
case 12: //Rainbow stripe colors case 12: //Rainbow stripe colors
targetPalette = RainbowStripeColors_p; break; targetPalette = RainbowStripeColors_p; break;
default: //progmem palettes default: //progmem palettes
load_gradient_palette(SEGMENT.palette -13); load_gradient_palette(paletteIndex -13);
} }
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode

View File

@ -71,6 +71,14 @@
#define BPIN 5 //B pin for analog LED strip #define BPIN 5 //B pin for analog LED strip
#define WPIN 15 //W pin for analog LED strip #define WPIN 15 //W pin for analog LED strip
#define W2PIN 12 //W2 pin for analog LED strip #define W2PIN 12 //W2 pin for analog LED strip
#elif defined(WLED_USE_PLJAKOBS_PCB)
// PWM pins - to use with esp_rgbww_controller from patrickjahns/pljakobs (https://github.com/pljakobs/esp_rgbww_controller)
#define RPIN 12 //R pin for analog LED strip
#define GPIN 13 //G pin for analog LED strip
#define BPIN 14 //B pin for analog LED strip
#define WPIN 4 //W pin for analog LED strip
#define W2PIN 5 //W2 pin for analog LED strip
#undef IR_PIN
#else #else
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller //PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
#define RPIN 5 //R pin for analog LED strip #define RPIN 5 //R pin for analog LED strip

View File

@ -10,6 +10,15 @@
#define DEFAULT_AP_PASS "wled1234" #define DEFAULT_AP_PASS "wled1234"
#define DEFAULT_OTA_PASS "wledota" #define DEFAULT_OTA_PASS "wledota"
//increase if you need more
#define WLED_MAX_USERMODS 4
//Usermod IDs
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
#define USERMOD_ID_EXAMPLE 2 //Usermod "usermod_v2_example.h"
#define USERMOD_ID_TEMPERATURE 3 //Usermod "usermod_temperature.h"
//Access point behavior //Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost) #define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
@ -44,6 +53,7 @@
#define REALTIME_MODE_E131 4 #define REALTIME_MODE_E131 4
#define REALTIME_MODE_ADALIGHT 5 #define REALTIME_MODE_ADALIGHT 5
#define REALTIME_MODE_ARTNET 6 #define REALTIME_MODE_ARTNET 6
#define REALTIME_MODE_TPM2NET 7
//realtime override modes //realtime override modes
#define REALTIME_OVERRIDE_NONE 0 #define REALTIME_OVERRIDE_NONE 0

View File

@ -927,7 +927,7 @@ input[type=number]::-webkit-outer-spin-button {
</label><br> </label><br>
First preset: <input id="cycs" class="noslide" type="number" min="1" max="14" value="1"><br> First preset: <input id="cycs" class="noslide" type="number" min="1" max="14" value="1"><br>
Last preset: <input id="cyce" class="noslide" type="number" min="2" max="15" value="3"><br> Last preset: <input id="cyce" class="noslide" type="number" min="2" max="15" value="3"><br>
Time per preset: <input id="cyct" class="noslide" type="number" min="0.2" max="65.5" step="0.1" value="1.2">s<br> Time per preset: <input id="cyct" class="noslide" type="number" min="0.2" max="6553.5" step="0.1" value="1.2">s<br>
Transition: <input id="cyctt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s Transition: <input id="cyctt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s
</div> </div>
</div> </div>

View File

@ -57,8 +57,10 @@ 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 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);
void changeBrightness(int8_t amount);
void changeEffectIntensity(int8_t amount); void changeEffectIntensity(int8_t amount);
void decodeIR(uint32_t code); void decodeIR(uint32_t code);
void decodeIR24(uint32_t code); void decodeIR24(uint32_t code);
@ -68,6 +70,7 @@ void decodeIR40(uint32_t code);
void decodeIR44(uint32_t code); void decodeIR44(uint32_t code);
void decodeIR21(uint32_t code); void decodeIR21(uint32_t code);
void decodeIR6(uint32_t code); void decodeIR6(uint32_t code);
void decodeIR9(uint32_t code);
void initIR(); void initIR();
void handleIR(); void handleIR();
@ -77,7 +80,6 @@ void handleIR();
#include "src/dependencies/json/ArduinoJson-v6.h" #include "src/dependencies/json/ArduinoJson-v6.h"
#include "src/dependencies/json/AsyncJson-v6.h" #include "src/dependencies/json/AsyncJson-v6.h"
#include "FX.h" #include "FX.h"
// TODO: AsynicWebServerRequest conflict?
void deserializeSegment(JsonObject elem, byte it); void deserializeSegment(JsonObject elem, byte it);
bool deserializeState(JsonObject root); bool deserializeState(JsonObject root);
@ -140,6 +142,40 @@ 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);
//um_manager.cpp
class Usermod {
public:
virtual void loop() {}
virtual void setup() {}
virtual void connected() {}
virtual void addToJsonState(JsonObject& obj) {}
virtual void addToJsonInfo(JsonObject& obj) {}
virtual void readFromJsonState(JsonObject& obj) {}
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
};
class UsermodManager {
private:
Usermod* ums[WLED_MAX_USERMODS];
byte numMods = 0;
public:
void loop();
void setup();
void connected();
void addToJsonState(JsonObject& obj);
void addToJsonInfo(JsonObject& obj);
void readFromJsonState(JsonObject& obj);
bool add(Usermod* um);
byte getModCount();
};
//usermods_list.cpp
void registerUsermods();
//usermod.cpp //usermod.cpp
void userSetup(); void userSetup();
void userConnected(); void userConnected();
@ -175,8 +211,8 @@ String dmxProcessor(const String& var);
void serveSettings(AsyncWebServerRequest* request); void serveSettings(AsyncWebServerRequest* request);
//xml.cpp //xml.cpp
char* XML_response(AsyncWebServerRequest *request, char* dest = nullptr); void XML_response(AsyncWebServerRequest *request, char* dest = nullptr);
char* URL_response(AsyncWebServerRequest *request); void URL_response(AsyncWebServerRequest *request);
void sappend(char stype, const char* key, int val); void sappend(char stype, const char* key, int val);
void sappends(char stype, const char* key, char* val); void sappends(char stype, const char* key, char* val);
void getSettingsJS(byte subPage, char* dest); void getSettingsJS(byte subPage, char* dest);

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,8 @@ decode_results results;
unsigned long irCheckedTime = 0; unsigned long irCheckedTime = 0;
uint32_t lastValidCode = 0; uint32_t lastValidCode = 0;
byte lastRepeatableAction = ACTION_NONE;
uint8_t lastRepeatableValue = 0;
uint16_t irTimesRepeated = 0; uint16_t irTimesRepeated = 0;
uint8_t lastIR6ColourIdx = 0; uint8_t lastIR6ColourIdx = 0;
@ -36,7 +38,7 @@ bool decodeIRCustom(uint32_t code)
} }
//relatively change brightness, minumum A=5
void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary) void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary)
{ {
int16_t new_val = (int16_t) *property + amount; int16_t new_val = (int16_t) *property + amount;
@ -45,6 +47,16 @@ void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte high
*property = (byte)constrain(new_val,0.1,255.1); *property = (byte)constrain(new_val,0.1,255.1);
} }
void changeBrightness(int8_t amount)
{
int16_t new_val = bri + amount;
if (new_val < 5) new_val = 5; //minimum brightness A=5
bri = (byte)constrain(new_val,0.1,255.1);
if(amount > 0) lastRepeatableAction = ACTION_BRIGHT_UP;
if(amount < 0) lastRepeatableAction = ACTION_BRIGHT_DOWN;
lastRepeatableValue = amount;
}
void changeEffectSpeed(int8_t amount) void changeEffectSpeed(int8_t amount)
{ {
if (effectCurrent != 0) { if (effectCurrent != 0) {
@ -65,6 +77,10 @@ void changeEffectSpeed(int8_t amount)
col[1] = fastled_col.green; col[1] = fastled_col.green;
col[2] = fastled_col.blue; col[2] = fastled_col.blue;
} }
if(amount > 0) lastRepeatableAction = ACTION_SPEED_UP;
if(amount < 0) lastRepeatableAction = ACTION_SPEED_DOWN;
lastRepeatableValue = amount;
} }
void changeEffectIntensity(int8_t amount) void changeEffectIntensity(int8_t amount)
@ -85,6 +101,10 @@ void changeEffectIntensity(int8_t amount)
col[1] = fastled_col.green; col[1] = fastled_col.green;
col[2] = fastled_col.blue; col[2] = fastled_col.blue;
} }
if(amount > 0) lastRepeatableAction = ACTION_INTENSITY_UP;
if(amount < 0) lastRepeatableAction = ACTION_INTENSITY_DOWN;
lastRepeatableValue = amount;
} }
void decodeIR(uint32_t code) void decodeIR(uint32_t code)
@ -92,14 +112,61 @@ void decodeIR(uint32_t code)
if (code == 0xFFFFFFFF) //repeated code, continue brightness up/down if (code == 0xFFFFFFFF) //repeated code, continue brightness up/down
{ {
irTimesRepeated++; irTimesRepeated++;
if (lastValidCode == IR24_BRIGHTER || lastValidCode == IR40_BPLUS ) applyRepeatActions();
return;
}
lastValidCode = 0; irTimesRepeated = 0;
if (decodeIRCustom(code)) return;
if (code > 0xFFFFFF) return; //invalid code
else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range
else if (code > 0xFF0000) {
switch (irEnabled) {
case 1: decodeIR24OLD(code); break; // white 24-key remote (old) - it sends 0xFF0000 values
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
case 5: decodeIR21(code); break; // white 21-key remote
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
// sets bright plain white
case 7: decodeIR9(code); break;
default: return;
}
}
if (nightlightActive && bri == 0) nightlightActive = false;
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //for notifier, IR is considered a button input
//code <= 0xF70000 also invalid
}
void applyRepeatActions(){
if (lastRepeatableAction == ACTION_BRIGHT_UP)
{ {
relativeChange(&bri, 10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
else if (lastValidCode == IR24_DARKER || lastValidCode == IR40_BMINUS ) else if (lastRepeatableAction == ACTION_BRIGHT_DOWN )
{ {
relativeChange(&bri, -10, 5); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
if (lastRepeatableAction == ACTION_SPEED_UP)
{
changeEffectSpeed(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
}
else if (lastRepeatableAction == ACTION_SPEED_DOWN )
{
changeEffectSpeed(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
}
if (lastRepeatableAction == ACTION_INTENSITY_UP)
{
changeEffectIntensity(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
}
else if (lastRepeatableAction == ACTION_INTENSITY_DOWN )
{
changeEffectIntensity(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
}
if (lastValidCode == IR40_WPLUS) if (lastValidCode == IR40_WPLUS)
{ {
relativeChangeWhite(10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); relativeChangeWhite(10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
@ -114,37 +181,14 @@ void decodeIR(uint32_t code)
nightlightStartTime = millis(); nightlightStartTime = millis();
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
return;
}
lastValidCode = 0; irTimesRepeated = 0;
if (decodeIRCustom(code)) return;
if (code > 0xFFFFFF) return; //invalid code
else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range
else if (code > 0xFF0000) {
switch (irEnabled) {
case 1: decodeIR24OLD(code); break; // white 24-key remote (old) - it sends 0xFF0000 values
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
case 5: decodeIR21(code); break; // white 21-key remote
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
// sets bright plain white
default: return;
}
}
if (nightlightActive && bri == 0) nightlightActive = false;
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //for notifier, IR is considered a button input
//code <= 0xF70000 also invalid
} }
void decodeIR24(uint32_t code) void decodeIR24(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_BRIGHTER : relativeChange(&bri, 10); break; case IR24_BRIGHTER : changeBrightness(10); break;
case IR24_DARKER : relativeChange(&bri, -10, 5); break; case IR24_DARKER : changeBrightness(-10); break;
case IR24_OFF : briLast = bri; bri = 0; break; case IR24_OFF : briLast = bri; bri = 0; break;
case IR24_ON : bri = briLast; break; case IR24_ON : bri = briLast; break;
case IR24_RED : colorFromUint32(COLOR_RED); break; case IR24_RED : colorFromUint32(COLOR_RED); break;
@ -175,8 +219,8 @@ void decodeIR24(uint32_t code)
void decodeIR24OLD(uint32_t code) void decodeIR24OLD(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_OLD_BRIGHTER : relativeChange(&bri, 10); break; case IR24_OLD_BRIGHTER : changeBrightness(10); break;
case IR24_OLD_DARKER : relativeChange(&bri, -10, 5); break; case IR24_OLD_DARKER : changeBrightness(-10); break;
case IR24_OLD_OFF : briLast = bri; bri = 0; break; case IR24_OLD_OFF : briLast = bri; bri = 0; break;
case IR24_OLD_ON : bri = briLast; break; case IR24_OLD_ON : bri = briLast; break;
case IR24_OLD_RED : colorFromUint32(COLOR_RED); break; case IR24_OLD_RED : colorFromUint32(COLOR_RED); break;
@ -208,8 +252,8 @@ void decodeIR24OLD(uint32_t code)
void decodeIR24CT(uint32_t code) void decodeIR24CT(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_CT_BRIGHTER : relativeChange(&bri, 10); break; case IR24_CT_BRIGHTER : changeBrightness(10); break;
case IR24_CT_DARKER : relativeChange(&bri, -10, 5); break; case IR24_CT_DARKER : changeBrightness(-10); break;
case IR24_CT_OFF : briLast = bri; bri = 0; break; case IR24_CT_OFF : briLast = bri; bri = 0; break;
case IR24_CT_ON : bri = briLast; break; case IR24_CT_ON : bri = briLast; break;
case IR24_CT_RED : colorFromUint32(COLOR_RED); break; case IR24_CT_RED : colorFromUint32(COLOR_RED); break;
@ -243,8 +287,8 @@ void decodeIR24CT(uint32_t code)
void decodeIR40(uint32_t code) void decodeIR40(uint32_t code)
{ {
switch (code) { switch (code) {
case IR40_BPLUS : relativeChange(&bri, 10); break; case IR40_BPLUS : changeBrightness(10); break;
case IR40_BMINUS : relativeChange(&bri, -10, 5); break; case IR40_BMINUS : changeBrightness(-10); break;
case IR40_OFF : briLast = bri; bri = 0; break; case IR40_OFF : briLast = bri; bri = 0; break;
case IR40_ON : bri = briLast; break; case IR40_ON : bri = briLast; break;
case IR40_RED : colorFromUint24(COLOR_RED); break; case IR40_RED : colorFromUint24(COLOR_RED); break;
@ -300,8 +344,8 @@ void decodeIR40(uint32_t code)
void decodeIR44(uint32_t code) void decodeIR44(uint32_t code)
{ {
switch (code) { switch (code) {
case IR44_BPLUS : relativeChange(&bri, 10); break; case IR44_BPLUS : changeBrightness(10); break;
case IR44_BMINUS : relativeChange(&bri, -10, 5); break; case IR44_BMINUS : changeBrightness(-10); break;
case IR44_OFF : briLast = bri; bri = 0; break; case IR44_OFF : briLast = bri; bri = 0; break;
case IR44_ON : bri = briLast; break; case IR44_ON : bri = briLast; break;
case IR44_RED : colorFromUint24(COLOR_RED); break; case IR44_RED : colorFromUint24(COLOR_RED); break;
@ -363,8 +407,8 @@ void decodeIR44(uint32_t code)
void decodeIR21(uint32_t code) void decodeIR21(uint32_t code)
{ {
switch (code) { switch (code) {
case IR21_BRIGHTER: relativeChange(&bri, 10); break; case IR21_BRIGHTER: changeBrightness(10); break;
case IR21_DARKER: relativeChange(&bri, -10, 5); break; case IR21_DARKER: changeBrightness(-10); break;
case IR21_OFF: briLast = bri; bri = 0; break; case IR21_OFF: briLast = bri; bri = 0; break;
case IR21_ON: bri = briLast; break; case IR21_ON: bri = briLast; break;
case IR21_RED: colorFromUint32(COLOR_RED); break; case IR21_RED: colorFromUint32(COLOR_RED); break;
@ -392,9 +436,9 @@ void decodeIR21(uint32_t code)
void decodeIR6(uint32_t code) void decodeIR6(uint32_t code)
{ {
switch (code) { switch (code) {
case IR6_POWER: toggleOnOff(); break; case IR6_POWER: toggleOnOff(); break;
case IR6_CHANNEL_UP: relativeChange(&bri, 10); break; case IR6_CHANNEL_UP: changeBrightness(10); break;
case IR6_CHANNEL_DOWN: relativeChange(&bri, -10, 5); break; case IR6_CHANNEL_DOWN: changeBrightness(-10); break;
case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect
case IR6_VOLUME_DOWN: // next palette case IR6_VOLUME_DOWN: // next palette
relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1); relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1);
@ -421,6 +465,24 @@ void decodeIR6(uint32_t code)
lastValidCode = code; lastValidCode = code;
} }
void decodeIR9(uint32_t code)
{
switch (code) {
case IR9_POWER : toggleOnOff(); break;
case IR9_A : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break;
case IR9_B : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break;
case IR9_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break;
case IR9_UP : changeBrightness(16); break;
case IR9_DOWN : changeBrightness(-16); break;
//case IR9_UP : changeEffectIntensity(16); break;
//case IR9_DOWN : changeEffectIntensity(-16); break;
case IR9_LEFT : changeEffectSpeed(-16); break;
case IR9_RIGHT : changeEffectSpeed(16); break;
case IR9_SELECT : relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break;
default: return;
}
lastValidCode = code;
}
void initIR() void initIR()
{ {

View File

@ -13,6 +13,15 @@
#define IR6_VOLUME_DOWN 0xFF2FD0 #define IR6_VOLUME_DOWN 0xFF2FD0
#define IR6_MUTE 0xFFAF50 #define IR6_MUTE 0xFFAF50
#define IR9_POWER 0xFF629D
#define IR9_A 0xFF22DD
#define IR9_B 0xFF02FD
#define IR9_C 0xFFC23D
#define IR9_LEFT 0xFF30CF
#define IR9_RIGHT 0xFF7A85
#define IR9_UP 0xFF9867
#define IR9_DOWN 0xFF38C7
#define IR9_SELECT 0xFF18E7
//Infrared codes for 24-key remote from http://woodsgood.ca/projects/2015/02/13/rgb-led-strip-controllers-ir-codes/ //Infrared codes for 24-key remote from http://woodsgood.ca/projects/2015/02/13/rgb-led-strip-controllers-ir-codes/
#define IR24_BRIGHTER 0xF700FF #define IR24_BRIGHTER 0xF700FF
@ -229,3 +238,12 @@
#define COLOR2_NEUTRALWHITE 0xFF000000 #define COLOR2_NEUTRALWHITE 0xFF000000
#define COLOR2_COLDWHITE 0xFF7F7F7F #define COLOR2_COLDWHITE 0xFF7F7F7F
#define COLOR2_COLDWHITE2 0xFFFFFFFF #define COLOR2_COLDWHITE2 0xFFFFFFFF
#define ACTION_NONE 0
#define ACTION_BRIGHT_UP 1
#define ACTION_BRIGHT_DOWN 2
#define ACTION_SPEED_UP 3
#define ACTION_SPEED_DOWN 4
#define ACTION_INTENSITY_UP 5
#define ACTION_INTENSITY_DOWN 6
#define ACTION_POWER 7

View File

@ -110,11 +110,7 @@ bool deserializeState(JsonObject root)
presetCycleMin = ccnf["min"] | presetCycleMin; presetCycleMin = ccnf["min"] | presetCycleMin;
presetCycleMax = ccnf["max"] | presetCycleMax; presetCycleMax = ccnf["max"] | presetCycleMax;
tr = ccnf["time"] | -1; tr = ccnf["time"] | -1;
if (tr >= 2) if (tr >= 2) presetCycleTime = tr;
{
presetCycleTime = tr;
presetCycleTime *= 100;
}
JsonObject nl = root["nl"]; JsonObject nl = root["nl"];
nightlightActive = nl["on"] | nightlightActive; nightlightActive = nl["on"] | nightlightActive;
@ -172,6 +168,8 @@ bool deserializeState(JsonObject root)
} }
} }
usermods.readFromJsonState(root);
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
//write presets to flash directly? //write presets to flash directly?
@ -237,11 +235,13 @@ void serializeState(JsonObject root)
root["pss"] = savedPresets; root["pss"] = savedPresets;
root["pl"] = (presetCyclingEnabled) ? 0: -1; root["pl"] = (presetCyclingEnabled) ? 0: -1;
//temporary for preser cycle usermods.addToJsonState(root);
//temporary for preset cycle
JsonObject ccnf = root.createNestedObject("ccnf"); JsonObject ccnf = root.createNestedObject("ccnf");
ccnf["min"] = presetCycleMin; ccnf["min"] = presetCycleMin;
ccnf["max"] = presetCycleMax; ccnf["max"] = presetCycleMax;
ccnf["time"] = presetCycleTime/100; ccnf["time"] = presetCycleTime;
JsonObject nl = root.createNestedObject("nl"); JsonObject nl = root.createNestedObject("nl");
nl["on"] = nightlightActive; nl["on"] = nightlightActive;
@ -319,8 +319,9 @@ void serializeInfo(JsonObject root)
case REALTIME_MODE_UDP: root["lm"] = "UDP"; break; case REALTIME_MODE_UDP: root["lm"] = "UDP"; break;
case REALTIME_MODE_HYPERION: root["lm"] = "Hyperion"; break; case REALTIME_MODE_HYPERION: root["lm"] = "Hyperion"; break;
case REALTIME_MODE_E131: root["lm"] = "E1.31"; break; case REALTIME_MODE_E131: root["lm"] = "E1.31"; break;
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight"); case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight/TPM2"); break;
case REALTIME_MODE_ARTNET: root["lm"] = "Art-Net"; break; case REALTIME_MODE_ARTNET: root["lm"] = "Art-Net"; break;
case REALTIME_MODE_TPM2NET: root["lm"] = F("tpm2.net"); break;
} }
if (realtimeIP[0] == 0) if (realtimeIP[0] == 0)
@ -365,6 +366,8 @@ void serializeInfo(JsonObject root)
root["freeheap"] = ESP.getFreeHeap(); root["freeheap"] = ESP.getFreeHeap();
root["uptime"] = millis()/1000 + rolloverMillis*4294967; root["uptime"] = millis()/1000 + rolloverMillis*4294967;
usermods.addToJsonInfo(root);
byte os = 0; byte os = 0;
#ifdef WLED_DEBUG #ifdef WLED_DEBUG

View File

@ -251,11 +251,12 @@ void handleNightlight()
} }
//also handle preset cycle here //also handle preset cycle here
if (presetCyclingEnabled && (millis() - presetCycledTime > presetCycleTime)) if (presetCyclingEnabled && (millis() - presetCycledTime > (100*presetCycleTime)))
{ {
if (presetCycCurr < presetCycleMin) presetCycCurr = presetCycleMin;
applyPreset(presetCycCurr,presetApplyBri); applyPreset(presetCycCurr,presetApplyBri);
presetCycCurr++; if (presetCycCurr > presetCycleMax) presetCycCurr = presetCycleMin; presetCycCurr++; if (presetCycCurr > presetCycleMax) presetCycCurr = presetCycleMin;
if (presetCycCurr > 25) presetCycCurr = 1; if (presetCycCurr > 16) presetCycCurr = 1;
colorUpdated(NOTIFIER_CALL_MODE_PRESET_CYCLE); colorUpdated(NOTIFIER_CALL_MODE_PRESET_CYCLE);
presetCycledTime = millis(); presetCycledTime = millis();
} }

View File

@ -76,7 +76,7 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
void publishMqtt() void publishMqtt()
{ {
doPublishMqtt = false; doPublishMqtt = false;
if (mqtt == nullptr || !mqtt->connected()) return; if (!WLED_MQTT_CONNECTED) return;
DEBUG_PRINTLN("Publish MQTT"); DEBUG_PRINTLN("Publish MQTT");
char s[10]; char s[10];

View File

@ -468,7 +468,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
pos = req.indexOf("PT="); //sets cycle time in ms pos = req.indexOf("PT="); //sets cycle time in ms
if (pos > 0) { if (pos > 0) {
int v = getNumVal(&req, pos); int v = getNumVal(&req, pos);
if (v > 49) presetCycleTime = v; if (v > 100) presetCycleTime = v/100;
} }
pos = req.indexOf("PA="); //apply brightness from preset pos = req.indexOf("PA="); //apply brightness from preset

View File

@ -1,7 +1,7 @@
#include "wled.h" #include "wled.h"
/* /*
* UDP sync notifier * UDP sync notifier / Realtime / Hyperion / TPM2.NET
*/ */
#define WLEDPACKETSIZE 29 #define WLEDPACKETSIZE 29
@ -89,6 +89,16 @@ void realtimeLock(uint32_t timeoutMs, byte md)
} }
#define TMP2NET_OUT_PORT 65442
void sendTPM2Ack() {
notifierUdp.beginPacket(notifierUdp.remoteIP(), TMP2NET_OUT_PORT);
uint8_t response_ack = 0xac;
notifierUdp.write(&response_ack, 1);
notifierUdp.endPacket();
}
void handleNotifications() void handleNotifications()
{ {
//send second notification if enabled //send second notification if enabled
@ -139,121 +149,151 @@ void handleNotifications()
} }
//notifier and UDP realtime //notifier and UDP realtime
if (packetSize > UDP_IN_MAXSIZE) return; if (!packetSize || packetSize > UDP_IN_MAXSIZE) return;
if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) //don't process broadcasts we send ourselves if (notifierUdp.remoteIP() == WiFi.localIP()) return; //don't process broadcasts we send ourselves
uint8_t udpIn[packetSize];
notifierUdp.read(udpIn, packetSize);
//wled notifier, block if realtime packets active
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
{ {
uint8_t udpIn[packetSize]; //ignore notification if received within a second after sending a notification ourselves
notifierUdp.read(udpIn, packetSize); if (millis() - notificationSentTime < 1000) return;
if (udpIn[1] > 199) return; //do not receive custom versions
//wled notifier, block if realtime packets active
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications) bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
//apply colors from notification
if (receiveNotificationColor || !someSel)
{ {
//ignore notification if received within a second after sending a notification ourselves col[0] = udpIn[3];
if (millis() - notificationSentTime < 1000) return; col[1] = udpIn[4];
if (udpIn[1] > 199) return; //do not receive custom versions col[2] = udpIn[5];
if (udpIn[11] > 0) //sending module's white val is intended
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
//apply colors from notification
if (receiveNotificationColor || !someSel)
{ {
col[0] = udpIn[3]; col[3] = udpIn[10];
col[1] = udpIn[4]; if (udpIn[11] > 1)
col[2] = udpIn[5];
if (udpIn[11] > 0) //sending module's white val is intended
{ {
col[3] = udpIn[10]; colSec[0] = udpIn[12];
if (udpIn[11] > 1) colSec[1] = udpIn[13];
{ colSec[2] = udpIn[14];
colSec[0] = udpIn[12]; colSec[3] = udpIn[15];
colSec[1] = udpIn[13]; }
colSec[2] = udpIn[14]; if (udpIn[11] > 5)
colSec[3] = udpIn[15]; {
} uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
if (udpIn[11] > 5) t += 2;
{ t -= millis();
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]); strip.timebase = t;
t += 2; }
t -= millis(); if (udpIn[11] > 6)
strip.timebase = t; {
} strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
if (udpIn[11] > 6)
{
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
}
} }
} }
//apply effects from notification
if (udpIn[11] < 200 && (receiveNotificationEffects || !someSel))
{
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
effectSpeed = udpIn[9];
if (udpIn[11] > 2) effectIntensity = udpIn[16];
if (udpIn[11] > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
}
if (udpIn[11] > 3)
{
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
}
nightlightActive = udpIn[6];
if (nightlightActive) nightlightDelayMins = udpIn[7];
if (receiveNotificationBrightness || !someSel) bri = udpIn[2];
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
} else if (udpIn[0] > 0 && udpIn[0] < 5 && receiveDirect) //1 warls //2 drgb //3 drgbw
{
realtimeIP = notifierUdp.remoteIP();
DEBUG_PRINTLN(notifierUdp.remoteIP());
if (packetSize < 2) return;
if (udpIn[1] == 0)
{
realtimeTimeout = 0;
return;
} else {
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
}
if (realtimeOverride) return;
if (udpIn[0] == 1) //warls
{
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2) //drgb
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 3) //drgbw
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 4) //dnrgb
{
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (uint16_t i = 4; i < packetSize -2; i += 3)
{
if (id >= ledCount) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++;
}
}
strip.show();
} }
//apply effects from notification
if (udpIn[11] < 200 && (receiveNotificationEffects || !someSel))
{
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
effectSpeed = udpIn[9];
if (udpIn[11] > 2) effectIntensity = udpIn[16];
if (udpIn[11] > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
}
if (udpIn[11] > 3)
{
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
}
nightlightActive = udpIn[6];
if (nightlightActive) nightlightDelayMins = udpIn[7];
if (receiveNotificationBrightness || !someSel) bri = udpIn[2];
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
}
if (!receiveDirect) return;
//TPM2.NET
if (udpIn[0] == 0x9c)
{
byte tpmType = udpIn[1];
if (tpmType == 0xaa) { //TPM2.NET polling, expect answer
sendTPM2Ack(); return;
}
if (tpmType != 0xda) return; //return if notTPM2.NET data
realtimeIP = notifierUdp.remoteIP();
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
if (realtimeOverride) return;
uint16_t frameSize = (udpIn[2] << 8) + udpIn[3];
byte packetNum = udpIn[4]; //starts with 1!
byte numPackets = udpIn[5];
uint16_t id = ((tpmFirstFrameSize/3)*(packetNum-1)) / 3; //start LED
for (uint16_t i = 6; i < frameSize + 4; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= ledCount) break;
}
if (packetNum == 1) tpmFirstFrameSize = frameSize;
if (packetNum == numPackets) {strip.show(); } //show if last packet
}
//UDP realtime: 1 warls 2 drgb 3 drgbw
if (udpIn[0] > 0 && udpIn[0] < 5)
{
realtimeIP = notifierUdp.remoteIP();
DEBUG_PRINTLN(notifierUdp.remoteIP());
if (packetSize < 2) return;
if (udpIn[1] == 0)
{
realtimeTimeout = 0;
return;
} else {
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
}
if (realtimeOverride) return;
if (udpIn[0] == 1) //warls
{
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2) //drgb
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 3) //drgbw
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 4) //dnrgb
{
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (uint16_t i = 4; i < packetSize -2; i += 3)
{
if (id >= ledCount) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++;
}
}
strip.show();
} }
} }

23
wled00/um_manager.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "wled.h"
/*
* Registration and management utility for v2 usermods
*/
//Usermod Manager internals
void UsermodManager::loop() { for (byte i = 0; i < numMods; i++) ums[i]->loop(); }
void UsermodManager::setup() { for (byte i = 0; i < numMods; i++) ums[i]->setup(); }
void UsermodManager::connected() { for (byte i = 0; i < numMods; i++) ums[i]->connected(); }
void UsermodManager::addToJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); }
void UsermodManager::addToJsonInfo(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); }
void UsermodManager::readFromJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); }
bool UsermodManager::add(Usermod* um)
{
if (numMods >= WLED_MAX_USERMODS || um == nullptr) return false;
ums[numMods] = um;
numMods++;
}
byte UsermodManager::getModCount() {return numMods;}

View File

@ -1,9 +1,11 @@
#include "wled.h" #include "wled.h"
/* /*
* This file allows you to add own functionality to WLED more easily * This v1 usermod file allows 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
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h) * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* bytes 2400+ are currently ununsed, but might be used for future wled features * 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) //Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)

18
wled00/usermod_v2_empty.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "wled.h"
//This is an empty v2 usermod template. Please see the file usermod_v2_example.h in the EXAMPLE_v2 usermod folder for documentation on the functions you can use!
class UsermodRenameMe : public Usermod {
private:
public:
void setup() {
}
void loop() {
}
};

26
wled00/usermods_list.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "wled.h"
/*
* Register your v2 usermods here!
* (for v1 usermods using just usermod.cpp, you can ignore this file)
*/
/*
* Add/uncomment your usermod filename here (and once more below)
* || || ||
* \/ \/ \/
*/
//#include "usermod_v2_example.h"
//#include "usermod_temperature.h"
//#include "usermod_v2_empty.h"
void registerUsermods()
{
/*
* Add your usermod class name here
* || || ||
* \/ \/ \/
*/
//usermods.add(new MyExampleUsermod());
//usermods.add(new UsermodTemperature());
//usermods.add(new UsermodRenameMe());
}

View File

@ -51,6 +51,7 @@ void WLED::loop()
handleDMX(); handleDMX();
#endif #endif
userLoop(); userLoop();
usermods.loop();
yield(); yield();
handleIO(); handleIO();
@ -94,35 +95,29 @@ void WLED::loop()
initMqtt(); initMqtt();
} }
// DEBUG serial logging // DEBUG serial logging
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
if (millis() - debugTime > 9999) { if (millis() - debugTime > 9999) {
DEBUG_PRINTLN("---DEBUG INFO---"); DEBUG_PRINTLN("---DEBUG INFO---");
DEBUG_PRINT("Runtime: "); DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis());
DEBUG_PRINTLN(millis()); DEBUG_PRINT("Unix time: "); DEBUG_PRINTLN(now());
DEBUG_PRINT("Unix time: "); DEBUG_PRINT("Free heap: "); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTLN(now()); DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status());
DEBUG_PRINT("Free heap: ");
DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINT("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("State time: "); DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime);
DEBUG_PRINTLN(wifiStateChangedTime); DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime);
DEBUG_PRINT("NTP last sync: "); DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP());
DEBUG_PRINTLN(ntpLastSyncTime); DEBUG_PRINT("Loops/sec: "); DEBUG_PRINTLN(loops / 10);
DEBUG_PRINT("Client IP: ");
DEBUG_PRINTLN(WiFi.localIP());
DEBUG_PRINT("Loops/sec: ");
DEBUG_PRINTLN(loops / 10);
loops = 0; loops = 0;
debugTime = millis(); debugTime = millis();
} }
loops++; loops++;
#endif // WLED_DEBU #endif // WLED_DEBUG
} }
void WLED::setup() void WLED::setup()
@ -156,6 +151,7 @@ void WLED::setup()
int heapPreAlloc = ESP.getFreeHeap(); int heapPreAlloc = ESP.getFreeHeap();
DEBUG_PRINT("heap "); DEBUG_PRINT("heap ");
DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINTLN(ESP.getFreeHeap());
registerUsermods();
strip.init(EEPROM.read(372), ledCount, EEPROM.read(2204)); // init LEDs quickly strip.init(EEPROM.read(372), ledCount, EEPROM.read(2204)); // init LEDs quickly
strip.setBrightness(0); strip.setBrightness(0);
@ -174,6 +170,7 @@ void WLED::setup()
loadSettingsFromEEPROM(true); loadSettingsFromEEPROM(true);
beginStrip(); beginStrip();
userSetup(); userSetup();
usermods.setup();
if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0) if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0)
showWelcomePage = true; showWelcomePage = true;
WiFi.persistent(false); WiFi.persistent(false);
@ -449,6 +446,7 @@ void WLED::handleConnection()
DEBUG_PRINTLN(WiFi.localIP()); DEBUG_PRINTLN(WiFi.localIP());
initInterfaces(); initInterfaces();
userConnected(); userConnected();
usermods.connected();
// shut down AP // shut down AP
if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) { if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) {

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2005100 #define VERSION 2006060
// ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS). // ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).
@ -25,7 +25,9 @@
//#define WLED_DISABLE_CRONIXIE // saves 3kb //#define WLED_DISABLE_CRONIXIE // saves 3kb
//#define WLED_DISABLE_HUESYNC // saves 4kb //#define WLED_DISABLE_HUESYNC // saves 4kb
//#define WLED_DISABLE_INFRARED // there is no pin left for this on ESP8266-01, saves 12kb //#define WLED_DISABLE_INFRARED // there is no pin left for this on ESP8266-01, saves 12kb
#define WLED_ENABLE_MQTT // saves 12kb #ifndef WLED_DISABLE_MQTT
#define WLED_ENABLE_MQTT // saves 12kb
#endif
#define WLED_ENABLE_ADALIGHT // saves 500b only #define WLED_ENABLE_ADALIGHT // saves 500b only
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2) //#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
@ -415,7 +417,7 @@ WLED_GLOBAL bool blynkEnabled _INIT(false);
// preset cycling // preset cycling
WLED_GLOBAL bool presetCyclingEnabled _INIT(false); WLED_GLOBAL bool presetCyclingEnabled _INIT(false);
WLED_GLOBAL byte presetCycleMin _INIT(1), presetCycleMax _INIT(5); WLED_GLOBAL byte presetCycleMin _INIT(1), presetCycleMax _INIT(5);
WLED_GLOBAL uint16_t presetCycleTime _INIT(1250); WLED_GLOBAL uint16_t presetCycleTime _INIT(12);
WLED_GLOBAL unsigned long presetCycledTime _INIT(0); WLED_GLOBAL unsigned long presetCycledTime _INIT(0);
WLED_GLOBAL byte presetCycCurr _INIT(presetCycleMin); WLED_GLOBAL byte presetCycCurr _INIT(presetCycleMin);
WLED_GLOBAL bool presetApplyBri _INIT(true); WLED_GLOBAL bool presetApplyBri _INIT(true);
@ -426,6 +428,7 @@ WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE); WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);
WLED_GLOBAL IPAddress realtimeIP _INIT((0, 0, 0, 0)); WLED_GLOBAL IPAddress realtimeIP _INIT((0, 0, 0, 0));
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0); WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
WLED_GLOBAL uint16_t tpmFirstFrameSize _INIT(0);
// mqtt // mqtt
WLED_GLOBAL long lastMqttReconnectAttempt _INIT(0); WLED_GLOBAL long lastMqttReconnectAttempt _INIT(0);
@ -490,6 +493,9 @@ WLED_GLOBAL bool e131NewData _INIT(false);
// led fx library object // led fx library object
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
// Usermod manager
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
// debug macro variable definitions // debug macro variable definitions
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
WLED_GLOBAL unsigned long debugTime _INIT(0); WLED_GLOBAL unsigned long debugTime _INIT(0);
@ -501,6 +507,7 @@ WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED)
#define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0) #define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0)
#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected())
// append new c string to temp buffer efficiently // append new c string to temp buffer efficiently
bool oappend(const char* txt); bool oappend(const char* txt);

View File

@ -7,7 +7,7 @@
*/ */
//eeprom Version code, enables default settings instead of 0 init on update //eeprom Version code, enables default settings instead of 0 init on update
#define EEPVER 20 #define EEPVER 21
//0 -> old version, default //0 -> old version, default
//1 -> 0.4p 1711272 and up //1 -> 0.4p 1711272 and up
//2 -> 0.4p 1711302 and up //2 -> 0.4p 1711302 and up
@ -29,6 +29,7 @@
//18-> 0.9.1-e131 //18-> 0.9.1-e131
//19-> 0.9.1n //19-> 0.9.1n
//20-> 0.9.1p //20-> 0.9.1p
//21-> 0.10.1p
void commit() void commit()
{ {
@ -547,6 +548,7 @@ void loadSettingsFromEEPROM(bool first)
{ {
presetCyclingEnabled = EEPROM.read(2205); presetCyclingEnabled = EEPROM.read(2205);
presetCycleTime = EEPROM.read(2206) + ((EEPROM.read(2207) << 8) & 0xFF00); presetCycleTime = EEPROM.read(2206) + ((EEPROM.read(2207) << 8) & 0xFF00);
if (lastEEPROMversion < 21) presetCycleTime /= 100; //was stored in ms, now is in tenths of a second
presetCycleMin = EEPROM.read(2208); presetCycleMin = EEPROM.read(2208);
presetCycleMax = EEPROM.read(2209); presetCycleMax = EEPROM.read(2209);
presetApplyBri = EEPROM.read(2210); presetApplyBri = EEPROM.read(2210);
@ -581,8 +583,10 @@ void loadSettingsFromEEPROM(bool first)
EEPROM.write(2550, DMXStartLED); EEPROM.write(2550, DMXStartLED);
#endif #endif
//user MOD memory //Usermod memory
//2944 - 3071 reserved //2551 - 2559 reserved for Usermods, usable by default
//2560 - 2943 usable, NOT reserved (need to increase EEPSIZE accordingly, new WLED core features may override this section)
//2944 - 3071 reserved for Usermods (need to increase EEPSIZE to 3072 in const.h)
overlayCurrent = overlayDefault; overlayCurrent = overlayDefault;

View File

@ -1,7 +1,7 @@
#include "wled.h" #include "wled.h"
/* /*
* Adalight handler * Adalight and TPM2 handler
*/ */
enum class AdaState { enum class AdaState {
@ -13,7 +13,10 @@ enum class AdaState {
Header_CountCheck, Header_CountCheck,
Data_Red, Data_Red,
Data_Green, Data_Green,
Data_Blue Data_Blue,
TPM2_Header_Type,
TPM2_Header_CountHi,
TPM2_Header_CountLo
}; };
void handleSerial() void handleSerial()
@ -33,6 +36,9 @@ void handleSerial()
switch (state) { switch (state) {
case AdaState::Header_A: case AdaState::Header_A:
if (next == 'A') state = AdaState::Header_d; if (next == 'A') state = AdaState::Header_d;
else if (next == 0xC9) { //TPM2 start byte
state = AdaState::TPM2_Header_Type;
}
break; break;
case AdaState::Header_d: case AdaState::Header_d:
if (next == 'd') state = AdaState::Header_a; if (next == 'd') state = AdaState::Header_a;
@ -57,6 +63,20 @@ void handleSerial()
if (check == next) state = AdaState::Data_Red; if (check == next) state = AdaState::Data_Red;
else state = AdaState::Header_A; else state = AdaState::Header_A;
break; break;
case AdaState::TPM2_Header_Type:
state = AdaState::Header_A; //(unsupported) TPM2 command or invalid type
if (next == 0xDA) state = AdaState::TPM2_Header_CountHi; //TPM2 data
else if (next == 0xAA) Serial.write(0xAC); //TPM2 ping
break;
case AdaState::TPM2_Header_CountHi:
pixel = 0;
count = (next * 0x100) /3;
state = AdaState::TPM2_Header_CountLo;
break;
case AdaState::TPM2_Header_CountLo:
count += next /3;
state = AdaState::Data_Red;
break;
case AdaState::Data_Red: case AdaState::Data_Red:
red = next; red = next;
state = AdaState::Data_Green; state = AdaState::Data_Green;

View File

@ -5,7 +5,7 @@
*/ */
//build XML response to HTTP /win API request //build XML response to HTTP /win API request
char* XML_response(AsyncWebServerRequest *request, char* dest) void XML_response(AsyncWebServerRequest *request, char* dest)
{ {
char sbuf[(dest == nullptr)?1024:1]; //allocate local buffer if none passed char sbuf[(dest == nullptr)?1024:1]; //allocate local buffer if none passed
obuf = (dest == nullptr)? sbuf:dest; obuf = (dest == nullptr)? sbuf:dest;
@ -77,7 +77,7 @@ char* XML_response(AsyncWebServerRequest *request, char* dest)
mesg += "."; mesg += ".";
mesg += realtimeIP[i]; mesg += realtimeIP[i];
} }
} else if (realtimeMode == REALTIME_MODE_UDP || realtimeMode == REALTIME_MODE_HYPERION) { } else if (realtimeMode == REALTIME_MODE_UDP || realtimeMode == REALTIME_MODE_HYPERION || realtimeMode == REALTIME_MODE_TPM2NET) {
mesg += "UDP from "; mesg += "UDP from ";
mesg += realtimeIP[0]; mesg += realtimeIP[0];
for (int i = 1; i < 4; i++) for (int i = 1; i < 4; i++)
@ -100,9 +100,9 @@ char* XML_response(AsyncWebServerRequest *request, char* dest)
if (request != nullptr) request->send(200, "text/xml", obuf); if (request != nullptr) request->send(200, "text/xml", obuf);
} }
char* URL_response(AsyncWebServerRequest *request) void URL_response(AsyncWebServerRequest *request)
{ {
char sbuf[256]; //allocate local buffer if none passed char sbuf[256];
char s2buf[100]; char s2buf[100];
obuf = s2buf; obuf = s2buf;
olen = 0; olen = 0;