Merge pull request #1658 from Aircoookie/mergedev-210115

Update multistrip dev branch
This commit is contained in:
Aircoookie 2021-01-15 11:15:04 +01:00 committed by GitHub
commit 25b77db4cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 4685 additions and 919 deletions

View File

@ -2,6 +2,31 @@
### Development versions after 0.11.1 release ### Development versions after 0.11.1 release
#### Build 2101130
- Added color transitions for all segments and slots and for segment brightness
- Fixed bug that prevented setting a boot preset higher than 25
#### Build 2101040
- Replaced Red & Blue effect with Aurora effect (PR #1589)
- Fixed HTTP changing segments uncommanded (#1618)
- Updated copyright year and contributor page link
#### Build 2012311
- Fixed Countdown mode
#### Build 2012310
- (Hopefully actually) fixed display of usermod values in info screen
#### Build 2012240
- Fixed display of usermod values in info screen
- 4 more effects now use FRAMETIME
- Remove unsupported environments from platformio.ini
#### Build 2012210 #### Build 2012210
- Split index.htm in separate CSS + JS files (PR #1542) - Split index.htm in separate CSS + JS files (PR #1542)

2889
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,8 +16,6 @@ default_envs = travis_esp8266, travis_esp32
# Single binaries (uncomment your board) # Single binaries (uncomment your board)
; default_envs = nodemcuv2 ; default_envs = nodemcuv2
; default_envs = esp01
; default_envs = esp01_1m_ota
; default_envs = esp01_1m_full ; default_envs = esp01_1m_full
; default_envs = esp07 ; default_envs = esp07
; default_envs = d1_mini ; default_envs = d1_mini
@ -120,6 +118,7 @@ build_flags =
-D DECODE_SAMSUNG=true -D DECODE_SAMSUNG=true
-D DECODE_LG=true -D DECODE_LG=true
-DWLED_USE_MY_CONFIG -DWLED_USE_MY_CONFIG
; -D USERMOD_SENSORSTOMQTT
build_unflags = build_unflags =
-Wall -Wall
@ -139,8 +138,6 @@ build_flags_all_features =
build_flags_esp8266 = ${common.build_flags} ${esp8266.build_flags} build_flags_esp8266 = ${common.build_flags} ${esp8266.build_flags}
build_flags_esp32 = ${common.build_flags} ${esp32.build_flags} build_flags_esp32 = ${common.build_flags} ${esp32.build_flags}
ldscript_512k = eagle.flash.512k.ld ;for older versions change this to eagle.flash.512k0.ld
ldscript_1m0m = eagle.flash.1m.ld ;for older versions change this to eagle.flash.1m0.ld
ldscript_1m128k = eagle.flash.1m128.ld ldscript_1m128k = eagle.flash.1m128.ld
ldscript_2m512k = eagle.flash.2m512.ld ldscript_2m512k = eagle.flash.2m512.ld
ldscript_2m1m = eagle.flash.2m1m.ld ldscript_2m1m = eagle.flash.2m1m.ld
@ -210,6 +207,10 @@ lib_deps =
#milesburton/DallasTemperature@^3.9.0 #milesburton/DallasTemperature@^3.9.0
#For BME280 sensor uncomment following #For BME280 sensor uncomment following
#BME280@~3.0.0 #BME280@~3.0.0
; adafruit/Adafruit BMP280 Library @ 2.1.0
; adafruit/Adafruit CCS811 Library @ 1.0.4
; adafruit/Adafruit Si7021 Library @ 1.4.0
lib_ignore = lib_ignore =
AsyncTCP AsyncTCP
@ -227,26 +228,6 @@ board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags} build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} build_flags = ${common.build_flags_esp8266}
# Unsupported environment due to insufficient flash
[env:esp01]
board = esp01
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_512k}
build_unflags = ${common.build_unflags}
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_MQTT -D WLED_DISABLE_WEBSOCKETS
# Unsupported environment due to insufficient flash
[env:esp01_1m_ota]
board = esp01_1m
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
build_unflags = ${common.build_unflags}
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 -D WLED_DISABLE_WEBSOCKETS
[env:esp01_1m_full] [env:esp01_1m_full]
board = esp01_1m board = esp01_1m
platform = ${common.platform_wled_default} platform = ${common.platform_wled_default}
@ -303,7 +284,7 @@ board = esp32-poe
platform = espressif32@2.0 platform = espressif32@2.0
upload_speed = 921600 upload_speed = 921600
build_unflags = ${common.build_unflags} build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D RLYPIN=-1 -D WLED_USE_ETHERNET build_flags = ${common.build_flags_esp32} -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
lib_ignore = lib_ignore =
ESPAsyncTCP ESPAsyncTCP
ESPAsyncUDP ESPAsyncUDP

View File

@ -3,14 +3,24 @@ This usermod allows use of the TTGO T-Display ESP32 module with integrated 240x1
for controlling WLED and showing the following information: for controlling WLED and showing the following information:
* Current SSID * Current SSID
* IP address if obtained * IP address if obtained
* in AP mode and turned off lightning AP password is shown * If connected to a network, current brightness % is shown
* in AP mode AP IP and password are shown
* Current effect * Current effect
* Current palette * Current palette
* Estimated current in mA is shown (NOTE: for this to be a reasonable value, the correct LED type must be specified in the LED Prefs section)
Button pin is mapped to the onboard button next to the side actuated reset button of the TTGO T-Display board.
I have designed a 3D printed case around this board and an ["ElectroCookie"](https://amzn.to/2WCNeeA) project board, a [level shifter](https://amzn.to/3hbKu18), a [buck regulator](https://amzn.to/3mLMy0W), and a DC [power jack](https://amzn.to/3phj9NZ). I use 12V WS2815 LED strips for my projects, and power them with 12V power supplies, so the regulator drops the voltage to the 5V level I need to power the ESP module and the level shifter. If there is any interest in this case, which elevates the board and display on some custom extended headers to make place the screen at the top of the enclosure (with accessible buttons), let me know, and I could post the STL files. It is a bit tricky to get the height correct, so I also designed a one-time use 3D printed solder fixture to set the board in the right location and at the correct height for the housing. (It is one-time use because it has to be cut off after soldering to be able to remove it). I didn't think the effort to make it in multiple pieces was worthwhile.
Usermod based on a rework of the ssd1306_i2c_oled_u8g2 usermod from the WLED repo. Usermod based on a rework of the ssd1306_i2c_oled_u8g2 usermod from the WLED repo.
## Hardware ## Hardware
![Hardware](assets/ttgo_hardware1.png) ![Hardware](assets/ttgo_hardware1.png)
![Hardware](assets/ttgo-tdisplay-enclosure1a.png)
![Hardware](assets/ttgo-tdisplay-enclosure2a.png)
![Hardware](assets/ttgo-tdisplay-enclosure3a.png)
![Hardware](assets/ttgo-tdisplay-enclosure3a.png)
## Github reference for TTGO-Tdisplay ## Github reference for TTGO-Tdisplay
@ -20,7 +30,11 @@ Usermod based on a rework of the ssd1306_i2c_oled_u8g2 usermod from the WLED rep
Functionality checked with: Functionality checked with:
* TTGO T-Display * TTGO T-Display
* PlatformIO * PlatformIO
* Group of 4 individual Neopixels from Adafruit, and a full string of 68 LEDs. * Group of 4 individual Neopixels from Adafruit, and a several full strings of 12v WS2815 LEDs.
* The hardware design shown above should be limited to shorter strings. For larger strings, I use a different setup with a dedicated 12v power supply and power them directly off the supply (in addition to dropping the 12v supply down to 5v with a buck regulator for the ESP module and level shifter).
## Setup Needed:
* As with all usermods, copy the usermod.cpp file from the TTGO-T-Display usermod folder to the wled00 folder (replacing the default usermod.cpp file).
## Platformio Requirements ## Platformio Requirements
### Platformio.ini changes ### Platformio.ini changes

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

View File

@ -56,7 +56,7 @@ void userSetup() {
tft.setTextColor(TFT_WHITE); tft.setTextColor(TFT_WHITE);
tft.setCursor(1, 10); tft.setCursor(1, 10);
tft.setTextDatum(MC_DATUM); tft.setTextDatum(MC_DATUM);
tft.setTextSize(2); tft.setTextSize(3);
tft.print("Loading..."); 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 if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
@ -142,22 +142,41 @@ void userLoop() {
tft.fillScreen(TFT_BLACK); tft.fillScreen(TFT_BLACK);
tft.setTextSize(2); tft.setTextSize(2);
// First row with Wifi name // First row with Wifi name
tft.setCursor(1, 10); tft.setCursor(1, 1);
tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0)); tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0));
// Print `~` char to indicate that SSID is longer, than our dicplay // Print `~` char to indicate that SSID is longer, than our dicplay
if (knownSsid.length() > tftcharwidth) if (knownSsid.length() > tftcharwidth)
tft.print("~"); tft.print("~");
// Second row with IP or Psssword // Second row with AP IP and Password or IP
tft.setCursor(1, 40); tft.setTextSize(2);
// Print password in AP mode and if led is OFF. tft.setCursor(1, 24);
if (apActive && bri == 0) // Print AP IP and password in AP mode or knownIP if AP not active.
tft.print(apPass); // if (apActive && bri == 0)
else // tft.print(apPass);
// else
// tft.print(knownIp);
if (apActive) {
tft.print("AP IP: ");
tft.print(knownIp); tft.print(knownIp);
tft.setCursor(1,46);
tft.print("AP Pass:");
tft.print(apPass);
}
else {
tft.print("IP: ");
tft.print(knownIp);
tft.setCursor(1,46);
//tft.print("Signal Strength: ");
//tft.print(i.wifi.signal);
tft.print("Brightness: ");
tft.print(((float(bri)/255)*100));
tft.print("%");
}
// Third row with mode name // Third row with mode name
tft.setCursor(1, 70); tft.setCursor(1, 68);
uint8_t qComma = 0; uint8_t qComma = 0;
bool insideQuotes = false; bool insideQuotes = false;
uint8_t printedChars = 0; uint8_t printedChars = 0;
@ -184,7 +203,7 @@ void userLoop() {
break; break;
} }
// Fourth row with palette name // Fourth row with palette name
tft.setCursor(1, 100); tft.setCursor(1, 90);
qComma = 0; qComma = 0;
insideQuotes = false; insideQuotes = false;
printedChars = 0; printedChars = 0;
@ -210,5 +229,10 @@ void userLoop() {
if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1)) if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1))
break; break;
} }
// Fifth row with estimated mA usage
tft.setCursor(1, 112);
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
tft.print(strip.currentMilliamps);
tft.print("mA (estimated)");
} }

View File

@ -0,0 +1,37 @@
# QuinLED-Dig-Quad Preassembled Unofficial Build
This usermod targets the [Preassembled QuinLED-Dig-Quad](https://quinled.info/pre-assembled-quinled-dig-quad/). Tested on board revision v1r6b,
and includes the following features:
* **Multi-channel Support** - enabling use of LED1, LED2, LED3, LED4 pins to work using segments
* **Temperature Sensor Support** - pulls readings from the built-in temperature sensor and adds the reading to the *Info* page in the UI
## Background
As a starting point, you should check out this awesome video from Quindor: [How to compile WLED yourself](https://quinled.info/2020/12/22/livestream-wled-compile/). The usermod you are reading now just provides some shortcuts for parts of what were covered in that video.
## Build Firmware with Multi-channel and Temp Support
1. Copy the `platformio_override.ini` file to the project's root directory
1. If using VS Code with the PlatformIO plugin like in the video, you will now see this new project task listed in the PLATFORMIO panel at the bottom as `env:QL-DigQuad-Pre-v0.1` (you probably need to hit the refresh button)
<img src="images/pio-screenshot.png" width="400px"/>
1. Edit this file from the root directory as needed:
<img src="images/params.png" width="400px"/>
* `PIXEL_COUNTS` may need to be adjusted for your set-up. E.g. I have lots of LEDs in Channel 1, but that's probably unusual for most
* `DATA_PINS` may need to be changed to "16,3,1,26" instead of "16,1,3,26" apparently depending on the board revision or some such
1. Build the mod (e.g. click `Build` from the project task circled above) and update your firmware using the `QL-DigQuad-Pre-v0.1` file, e.g. using _Manual OTA_ from the Config menu. Based on the video and my own experience, you might need to build twice 🤷‍♂️.
## Observing Temperature
Hopefully you can now see the Temperature listed in the Info page. If not, use Chrome Developer Tools to find the current temperature
1. Open the Developer Tools Console
2. Enter `lastinfo.u.Temperature` to view the Temperature array
<img src="images/json-temp.png" width="300px"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

View File

@ -0,0 +1,16 @@
; QuinLED-Dig-Quad Preassembled Unofficial
[env:QL-DigQuad-Pre-v0.1]
extends = env:esp32dev
build_flags = ${common.build_flags_esp32}
-D ESP32_MULTISTRIP
-D NUM_STRIPS=4
-D PIXEL_COUNTS="600, 300, 300, 300"
-D DATA_PINS="16,1,3,26"
-D RLYPIN=19
-D BTNPIN=17
-D USERMOD_DALLASTEMPERATURE
-D USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL=10000
lib_deps = ${env.lib_deps}
milesburton/DallasTemperature@^3.9.0
OneWire@~2.3.5

View File

@ -0,0 +1,87 @@
# Sensors To Home Assistant (or mqtt)
This usermod will publish values of the BMP280, CCS811 and Si7021 sensors to Home Assistant via MQTT.
Its using home assistant automatic device discovery feature.
The use of Home Assistant is not mandatory; it will publish the sensor values via MQTT just fine without it.
Its resusing the mqtt connection set in the WLED web user interface.
## Maintainer
twitter.com/mpronk89
## Features
- Reads BMP280, CCS811 and Si7021 senors
- Publishes via MQTT, configured via webui of wled
- Announces device in Home Assistant for easy setup
- Efficient energy usage
- Updates every 60 seconds
## Example mqtt topics:
`$mqttDeviceTopic` is set in webui of WLED!
```
temperature: $mqttDeviceTopic/temperature
pressure: $mqttDeviceTopic/pressure
humidity: $mqttDeviceTopic/humidity
tvoc: $mqttDeviceTopic/tvoc
eCO2: $mqttDeviceTopic/eco2
IAQ: $mqttDeviceTopic/iaq
```
# Installation
## Hardware
### Requirements
1. BMP280/CCS811/Si7021 sensor. E.g. https://aliexpress.com/item/32979998543.html
2. A microcontroller which can talk i2c, e.g. esp32
### installation
Attach the sensor to the i2c interface.
Default PINs esp32:
```
SCL_PIN = 22;
SDA_PIN = 21;
```
Default PINs ESP8266:
```
SCL_PIN = 5;
SDA_PIN = 4;
```
## Enable in WLED
1. Copy `usermod_v2_SensorsToMqtt.h` into the `wled00` directory.
2. Add to `build_flags` in platformio.ini:
```
-D USERMOD_SENSORSTOMQTT
```
3. And add to `lib_deps` in platformio.ini:
```
adafruit/Adafruit BMP280 Library @ 2.1.0
adafruit/Adafruit CCS811 Library @ 1.0.4
adafruit/Adafruit Si7021 Library @ 1.4.0
```
The #ifdefs in `usermods_list.cpp` should do the rest :)
# Credits
- Aircoookie for making WLED
- Other usermod creators for example code
- Bouke_Regnerus for https://community.home-assistant.io/t/example-indoor-air-quality-text-sensor-using-ccs811-sensor/125854
- You, for reading this

View File

@ -0,0 +1,284 @@
#pragma once
#include "wled.h"
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_CCS811.h>
#include <Adafruit_Si7021.h>
Adafruit_BMP280 bmp;
Adafruit_Si7021 si7021;
Adafruit_CCS811 ccs811;
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
uint8_t SCL_PIN = 22;
uint8_t SDA_PIN = 21;
#else //ESP8266 boards
uint8_t SCL_PIN = 5;
uint8_t SDA_PIN = 4;
#endif
class UserMod_SensorsToMQTT : public Usermod
{
private:
bool initialized = false;
bool mqttInitialized = false;
float SensorPressure = 0;
float SensorTemperature = 0;
float SensorHumidity = 0;
char *SensorIaq = "Unknown";
String mqttTemperatureTopic = "";
String mqttHumidityTopic = "";
String mqttPressureTopic = "";
String mqttTvocTopic = "";
String mqttEco2Topic = "";
String mqttIaqTopic = "";
unsigned int SensorTvoc = 0;
unsigned int SensorEco2 = 0;
unsigned long nextMeasure = 0;
void _initialize()
{
initialized = bmp.begin(BMP280_ADDRESS_ALT);
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X16, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_2000); /* Refresh values every 20 seconds */
initialized &= si7021.begin();
initialized &= ccs811.begin();
ccs811.setDriveMode(CCS811_DRIVE_MODE_10SEC); /* Refresh values every 10s */
Serial.print(initialized);
}
void _mqttInitialize()
{
mqttTemperatureTopic = String(mqttDeviceTopic) + "/temperature";
mqttPressureTopic = String(mqttDeviceTopic) + "/pressure";
mqttHumidityTopic = String(mqttDeviceTopic) + "/humidity";
mqttTvocTopic = String(mqttDeviceTopic) + "/tvoc";
mqttEco2Topic = String(mqttDeviceTopic) + "/eco2";
mqttIaqTopic = String(mqttDeviceTopic) + "/iaq";
String t = String("homeassistant/sensor/") + mqttClientID + "/temperature/config";
_createMqttSensor("temperature", mqttTemperatureTopic, "temperature", "°C");
_createMqttSensor("pressure", mqttPressureTopic, "pressure", "hPa");
_createMqttSensor("humidity", mqttHumidityTopic, "humidity", "%");
_createMqttSensor("tvoc", mqttTvocTopic, "", "ppb");
_createMqttSensor("eco2", mqttEco2Topic, "", "ppm");
_createMqttSensor("iaq", mqttIaqTopic, "", "");
}
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
{
String t = String("homeassistant/sensor/") + mqttClientID + "/" + name + "/config";
StaticJsonDocument<300> doc;
doc["name"] = name;
doc["state_topic"] = topic;
doc["unique_id"] = String(mqttClientID) + name;
if (unitOfMeasurement != "")
doc["unit_of_measurement"] = unitOfMeasurement;
if (deviceClass != "")
doc["device_class"] = deviceClass;
doc["expire_after"] = 1800;
JsonObject device = doc.createNestedObject("device"); // attach the sensor to the same device
device["identifiers"] = String("wled-sensor-") + mqttClientID;
device["manufacturer"] = "Aircoookie";
device["model"] = "WLED";
device["sw_version"] = VERSION;
device["name"] = mqttClientID;
String temp;
serializeJson(doc, temp);
Serial.println(t);
Serial.println(temp);
mqtt->publish(t.c_str(), 0, true, temp.c_str());
}
void _updateSensorData()
{
SensorTemperature = bmp.readTemperature();
SensorHumidity = si7021.readHumidity();
SensorPressure = (bmp.readPressure() / 100.0F);
ccs811.setEnvironmentalData(SensorHumidity, SensorTemperature);
ccs811.readData();
SensorTvoc = ccs811.getTVOC();
SensorEco2 = ccs811.geteCO2();
SensorIaq = _getIaqIndex(SensorHumidity, SensorTvoc, SensorEco2);
Serial.printf("%f c, %f humidity, %f hPA, %u tvoc, %u Eco2, %s iaq\n",
SensorTemperature, SensorHumidity, SensorPressure,
SensorTvoc, SensorEco2, SensorIaq);
}
/**
* Credits: Bouke_Regnerus @ https://community.home-assistant.io/t/example-indoor-air-quality-text-sensor-using-ccs811-sensor/125854
*/
char *_getIaqIndex(float humidity, int tvoc, int eco2)
{
int iaq_index = 0;
/*
* Transform indoor humidity values to IAQ points according to Indoor Air Quality UK:
* http://www.iaquk.org.uk/
*/
if (humidity < 10 or humidity > 90)
{
iaq_index += 1;
}
else if (humidity < 20 or humidity > 80)
{
iaq_index += 2;
}
else if (humidity < 30 or humidity > 70)
{
iaq_index += 3;
}
else if (humidity < 40 or humidity > 60)
{
iaq_index += 4;
}
else if (humidity >= 40 and humidity <= 60)
{
iaq_index += 5;
}
/*
* Transform eCO2 values to IAQ points according to Indoor Air Quality UK:
* http://www.iaquk.org.uk/
*/
if (eco2 <= 600)
{
iaq_index += 5;
}
else if (eco2 <= 800)
{
iaq_index += 4;
}
else if (eco2 <= 1500)
{
iaq_index += 3;
}
else if (eco2 <= 1800)
{
iaq_index += 2;
}
else if (eco2 > 1800)
{
iaq_index += 1;
}
/*
* Transform TVOC values to IAQ points according to German environmental guidelines:
* https://www.repcomsrl.com/wp-content/uploads/2017/06/Environmental_Sensing_VOC_Product_Brochure_EN.pdf
*/
if (tvoc <= 65)
{
iaq_index += 5;
}
else if (tvoc <= 220)
{
iaq_index += 4;
}
else if (tvoc <= 660)
{
iaq_index += 3;
}
else if (tvoc <= 2200)
{
iaq_index += 2;
}
else if (tvoc > 2200)
{
iaq_index += 1;
}
if (iaq_index <= 6)
{
return "Unhealty";
}
else if (iaq_index <= 9)
{
return "Poor";
}
else if (iaq_index <= 12)
{
return "Moderate";
}
else if (iaq_index <= 14)
{
return "Good";
}
else if (iaq_index > 14)
{
return "Excellent";
}
}
public:
void setup()
{
Serial.println("Starting!");
Wire.begin(SDA_PIN, SCL_PIN);
Serial.println("Initializing sensors.. ");
_initialize();
}
// gets called every time WiFi is (re-)connected.
void connected()
{
nextMeasure = millis() + 5000; // Schedule next measure in 5 seconds
}
void loop()
{
unsigned long tempTimer = millis();
if (tempTimer > nextMeasure)
{
nextMeasure = tempTimer + 60000; // Schedule next measure in 60 seconds
if (!initialized)
{
Serial.println("Error! Sensors not initialized in loop()!");
_initialize();
return; // lets try again next loop
}
if (mqtt != nullptr && mqtt->connected())
{
if (!mqttInitialized)
{
_mqttInitialize();
mqttInitialized = true;
}
// Update sensor data
_updateSensorData();
// Create string populated with user defined device topic from the UI,
// and the read temperature, humidity and pressure.
// Then publish to MQTT server.
mqtt->publish(mqttTemperatureTopic.c_str(), 0, true, String(SensorTemperature).c_str());
mqtt->publish(mqttPressureTopic.c_str(), 0, true, String(SensorPressure).c_str());
mqtt->publish(mqttHumidityTopic.c_str(), 0, true, String(SensorHumidity).c_str());
mqtt->publish(mqttTvocTopic.c_str(), 0, true, String(SensorTvoc).c_str());
mqtt->publish(mqttEco2Topic.c_str(), 0, true, String(SensorEco2).c_str());
mqtt->publish(mqttIaqTopic.c_str(), 0, true, String(SensorIaq).c_str());
}
else
{
Serial.println("Missing MQTT connection. Not publishing data");
mqttInitialized = false;
}
}
}
};

View File

@ -30,7 +30,6 @@
#define IBN 5100 #define IBN 5100
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3) #define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
/* /*
* No blinking. Just plain old static light. * No blinking. Just plain old static light.
*/ */
@ -594,7 +593,7 @@ uint16_t WS2812FX::mode_sparkle(void) {
/* /*
* Lights all LEDs in the color. Flashes single white pixels randomly. * Lights all LEDs in the color. Flashes single col 1 pixels randomly. (List name: Sparkle Dark)
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/ */
uint16_t WS2812FX::mode_flash_sparkle(void) { uint16_t WS2812FX::mode_flash_sparkle(void) {
@ -602,12 +601,14 @@ uint16_t WS2812FX::mode_flash_sparkle(void) {
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
} }
if(random8(5) == 0) { if (now - SEGENV.aux0 > SEGENV.step) {
SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index if(random8((255-SEGMENT.intensity) >> 4) == 0) {
setPixelColor(SEGENV.aux0, SEGCOLOR(1)); setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash
return 20;
} }
return 20 + (uint16_t)(255-SEGMENT.speed); SEGENV.step = now;
SEGENV.aux0 = 255-SEGMENT.speed;
}
return FRAMETIME;
} }
@ -620,13 +621,16 @@ uint16_t WS2812FX::mode_hyper_sparkle(void) {
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
} }
if(random8(5) < 2) { if (now - SEGENV.aux0 > SEGENV.step) {
if(random8((255-SEGMENT.intensity) >> 4) == 0) {
for(uint16_t i = 0; i < MAX(1, SEGLEN/3); i++) { for(uint16_t i = 0; i < MAX(1, SEGLEN/3); i++) {
setPixelColor(random16(SEGLEN), SEGCOLOR(1)); setPixelColor(random16(SEGLEN), SEGCOLOR(1));
} }
return 20;
} }
return 20 + (uint16_t)(255-SEGMENT.speed); SEGENV.step = now;
SEGENV.aux0 = 255-SEGMENT.speed;
}
return FRAMETIME;
} }
@ -637,22 +641,25 @@ uint16_t WS2812FX::mode_multi_strobe(void) {
for(uint16_t i = 0; i < SEGLEN; i++) { for(uint16_t i = 0; i < SEGLEN; i++) {
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
} }
//blink(SEGCOLOR(0), SEGCOLOR(1), true, true);
uint16_t delay = 50 + 20*(uint16_t)(255-SEGMENT.speed); SEGENV.aux0 = 50 + 20*(uint16_t)(255-SEGMENT.speed);
uint16_t count = 2 * ((SEGMENT.speed / 10) + 1); uint16_t count = 2 * ((SEGMENT.intensity / 10) + 1);
if(SEGENV.step < count) { if(SEGENV.aux1 < count) {
if((SEGENV.step & 1) == 0) { if((SEGENV.aux1 & 1) == 0) {
for(uint16_t i = 0; i < SEGLEN; i++) { fill(SEGCOLOR(0));
setPixelColor(i, SEGCOLOR(0)); SEGENV.aux0 = 15;
}
delay = 20;
} else { } else {
delay = 50; SEGENV.aux0 = 50;
} }
} }
SEGENV.step = (SEGENV.step + 1) % (count + 1);
return delay; if (now - SEGENV.aux0 > SEGENV.step) {
SEGENV.aux1++;
if (SEGENV.aux1 > count) SEGENV.aux1 = 0;
SEGENV.step = now;
}
return FRAMETIME;
} }
/* /*
@ -995,14 +1002,6 @@ uint16_t WS2812FX::mode_running_color(void) {
} }
/*
* Alternating red/blue pixels running.
*/
uint16_t WS2812FX::mode_running_red_blue(void) {
return running(RED, BLUE);
}
/* /*
* Alternating red/green pixels running. * Alternating red/green pixels running.
*/ */
@ -1623,37 +1622,39 @@ uint16_t WS2812FX::mode_lightning(void)
uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
uint8_t bri = 255/random8(1, 3); uint8_t bri = 255/random8(1, 3);
if (SEGENV.step == 0) if (SEGENV.aux1 == 0) //init, leader flash
{ {
SEGENV.aux0 = random8(3, 3 + SEGMENT.intensity/20); //number of flashes SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity/20); //number of flashes
bri = 52; SEGENV.aux1 *= 2;
SEGENV.aux1 = 1;
bri = 52; //leader has lower brightness
SEGENV.aux0 = 200; //200ms delay after leader
} }
fill(SEGCOLOR(1)); fill(SEGCOLOR(1));
if (SEGENV.aux1) { if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
for (int i = ledstart; i < ledstart + ledlen; i++) for (int i = ledstart; i < ledstart + ledlen; i++)
{ {
if (SEGMENT.palette == 0)
{
setPixelColor(i,bri,bri,bri,bri);
} else {
setPixelColor(i,color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri)); setPixelColor(i,color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri));
} }
SEGENV.aux1--;
SEGENV.step = millis();
//return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds
} else {
if (millis() - SEGENV.step > SEGENV.aux0) {
SEGENV.aux1--;
if (SEGENV.aux1 < 2) SEGENV.aux1 = 0;
SEGENV.aux0 = (50 + random8(100)); //delay between flashes
if (SEGENV.aux1 == 2) {
SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes
} }
SEGENV.aux1 = 0; SEGENV.step = millis();
SEGENV.step++;
return random8(4, 10); // each flash only lasts 4-10 milliseconds
} }
}
SEGENV.aux1 = 1; return FRAMETIME;
if (SEGENV.step == 1) return (200); // longer delay until next flash after the leader
if (SEGENV.step <= SEGENV.aux0) return (50 + random8(100)); // shorter delay between strokes
SEGENV.step = 0;
return (random8(255 - SEGMENT.speed) * 100); // delay between strikes
} }
@ -3870,3 +3871,153 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
return FRAMETIME; return FRAMETIME;
#endif #endif
} }
/*
Aurora effect
*/
//CONFIG
#define BACKLIGHT 5
#define W_MAX_COUNT 20 //Number of simultaneous waves
#define W_MAX_SPEED 6 //Higher number, higher speed
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
class AuroraWave {
private:
uint16_t ttl;
CRGB basecolor;
float basealpha;
uint16_t age;
uint16_t width;
float center;
bool goingleft;
float speed_factor;
bool alive = true;
public:
void init(uint32_t segment_length, CRGB color) {
ttl = random(500, 1501);
basecolor = color;
basealpha = random(60, 101) / (float)100;
age = 0;
width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
if (!width) width = 1;
center = random(101) / (float)100 * segment_length;
goingleft = random(0, 2) == 0;
speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255);
alive = true;
}
CRGB getColorForLED(int ledIndex) {
if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave
CRGB rgb;
//Offset of this led from center of wave
//The further away from the center, the dimmer the LED
float offset = ledIndex - center;
if (offset < 0) offset = -offset;
float offsetFactor = offset / width;
//The age of the wave determines it brightness.
//At half its maximum age it will be the brightest.
float ageFactor = 0.1;
if((float)age / ttl < 0.5) {
ageFactor = (float)age / (ttl / 2);
} else {
ageFactor = (float)(ttl - age) / ((float)ttl * 0.5);
}
//Calculate color based on above factors and basealpha value
float factor = (1 - offsetFactor) * ageFactor * basealpha;
rgb.r = basecolor.r * factor;
rgb.g = basecolor.g * factor;
rgb.b = basecolor.b * factor;
return rgb;
};
//Change position and age of wave
//Determine if its sill "alive"
void update(uint32_t segment_length, uint32_t speed) {
if(goingleft) {
center -= speed_factor * speed;
} else {
center += speed_factor * speed;
}
age++;
if(age > ttl) {
alive = false;
} else {
if(goingleft) {
if(center + width < 0) {
alive = false;
}
} else {
if(center - width > segment_length) {
alive = false;
}
}
}
};
bool stillAlive() {
return alive;
};
};
uint16_t WS2812FX::mode_aurora(void) {
//aux1 = Wavecount
//aux2 = Intensity in last loop
AuroraWave* waves;
if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
//Intensity slider changed or first call
SEGENV.aux1 = ((float)SEGMENT.intensity / 255) * W_MAX_COUNT;
SEGENV.aux0 = SEGMENT.intensity;
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) {
return mode_static(); //allocation failed
}
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
for(int i = 0; i < SEGENV.aux1; i++) {
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
}
} else {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
}
for(int i = 0; i < SEGENV.aux1; i++) {
//Update values of wave
waves[i].update(SEGLEN, SEGMENT.speed);
if(!(waves[i].stillAlive())) {
//If a wave dies, reinitialize it starts over.
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
}
}
//Loop through LEDs to determine color
for(int i = 0; i < SEGLEN; i++) {
CRGB mixedRgb = CRGB(BACKLIGHT, BACKLIGHT, BACKLIGHT);
//For each LED we must check each wave if it is "active" at this position.
//If there are multiple waves active on a LED we multiply their values.
for(int j = 0; j < SEGENV.aux1; j++) {
CRGB rgb = waves[j].getColorForLED(i);
if(rgb != CRGB(0)) {
mixedRgb += rgb;
}
}
setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2], BACKLIGHT);
}
return FRAMETIME;
}

View File

@ -63,15 +63,14 @@
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#ifdef ESP8266 #ifdef ESP8266
#define MAX_NUM_SEGMENTS 12 #define MAX_NUM_SEGMENTS 12
/* How many color transitions can run at once */
#define MAX_NUM_TRANSITIONS 8
/* How much data bytes all segments combined may allocate */
#define MAX_SEGMENT_DATA 2048
#else #else
#define MAX_NUM_SEGMENTS 16 #define MAX_NUM_SEGMENTS 16
#endif #define MAX_NUM_TRANSITIONS 16
#define MAX_SEGMENT_DATA 8192
/* How much data bytes all segments combined may allocate */
#ifdef ESP8266
#define MAX_SEGMENT_DATA 2048
#else
#define MAX_SEGMENT_DATA 8192
#endif #endif
#define LED_SKIP_AMOUNT 1 #define LED_SKIP_AMOUNT 1
@ -79,7 +78,7 @@
#define NUM_COLORS 3 /* number of colors per segment */ #define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT _segments[_segment_index] #define SEGMENT _segments[_segment_index]
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x]) #define SEGCOLOR(x) _colors_t[x]
#define SEGENV _segment_runtimes[_segment_index] #define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN _virtualSegmentLength #define SEGLEN _virtualSegmentLength
#define SEGACT SEGMENT.stop #define SEGACT SEGMENT.stop
@ -119,7 +118,6 @@
#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 118 #define MODE_COUNT 118
#define FX_MODE_STATIC 0 #define FX_MODE_STATIC 0
@ -160,7 +158,7 @@
#define FX_MODE_TRAFFIC_LIGHT 35 #define FX_MODE_TRAFFIC_LIGHT 35
#define FX_MODE_COLOR_SWEEP_RANDOM 36 #define FX_MODE_COLOR_SWEEP_RANDOM 36
#define FX_MODE_RUNNING_COLOR 37 #define FX_MODE_RUNNING_COLOR 37
#define FX_MODE_RUNNING_RED_BLUE 38 #define FX_MODE_AURORA 38
#define FX_MODE_RUNNING_RANDOM 39 #define FX_MODE_RUNNING_RANDOM 39
#define FX_MODE_LARSON_SCANNER 40 #define FX_MODE_LARSON_SCANNER 40
#define FX_MODE_COMET 41 #define FX_MODE_COMET 41
@ -241,12 +239,15 @@
#define FX_MODE_TV_SIMULATOR 116 #define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117 #define FX_MODE_DYNAMIC_SMOOTH 117
class WS2812FX { class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void); typedef uint16_t (WS2812FX::*mode_ptr)(void);
// pre show callback // pre show callback
typedef void (*show_callback) (void); typedef void (*show_callback) (void);
static WS2812FX* instance;
// segment parameters // segment parameters
public: public:
typedef struct Segment { // 24 bytes typedef struct Segment { // 24 bytes
@ -260,14 +261,40 @@ class WS2812FX {
uint8_t grouping, spacing; uint8_t grouping, spacing;
uint8_t opacity; uint8_t opacity;
uint32_t colors[NUM_COLORS]; uint32_t colors[NUM_COLORS];
void setOption(uint8_t n, bool val) bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
if (c == colors[slot]) return false;
ColorTransition::startTransition(opacity, colors[slot], instance->_transitionDur, segn, slot);
colors[slot] = c; return true;
}
void setOpacity(uint8_t o, uint8_t segn) {
if (segn >= MAX_NUM_SEGMENTS) return;
if (opacity == o) return;
ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
opacity = o;
}
/*uint8_t actualOpacity() { //respects On/Off state
if (!getOption(SEG_OPTION_ON)) return 0;
return opacity;
}*/
void setOption(uint8_t n, bool val, uint8_t segn = 255)
{ {
//bool prevOn = false;
//if (n == SEG_OPTION_ON) prevOn = getOption(SEG_OPTION_ON);
if (val) { if (val) {
options |= 0x01 << n; options |= 0x01 << n;
} else } else
{ {
options &= ~(0x01 << n); options &= ~(0x01 << n);
} }
//transitions on segment on/off don't work correctly at this point
/*if (n == SEG_OPTION_ON && segn < MAX_NUM_SEGMENTS && getOption(SEG_OPTION_ON) != prevOn) {
if (getOption(SEG_OPTION_ON)) {
ColorTransition::startTransition(0, colors[0], instance->_transitionDur, segn, 0);
} else {
ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
}
}*/
} }
bool getOption(uint8_t n) bool getOption(uint8_t n)
{ {
@ -310,10 +337,10 @@ class WS2812FX {
bool allocateData(uint16_t len){ bool allocateData(uint16_t len){
if (data && _dataLen == len) return true; //already allocated if (data && _dataLen == len) return true; //already allocated
deallocateData(); deallocateData();
if (WS2812FX::_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
data = new (std::nothrow) byte[len]; data = new (std::nothrow) byte[len];
if (!data) return false; //allocation failed if (!data) return false; //allocation failed
WS2812FX::_usedSegmentData += len; WS2812FX::instance->_usedSegmentData += len;
_dataLen = len; _dataLen = len;
memset(data, 0, len); memset(data, 0, len);
return true; return true;
@ -321,7 +348,7 @@ class WS2812FX {
void deallocateData(){ void deallocateData(){
delete[] data; delete[] data;
data = nullptr; data = nullptr;
WS2812FX::_usedSegmentData -= _dataLen; WS2812FX::instance->_usedSegmentData -= _dataLen;
_dataLen = 0; _dataLen = 0;
} }
@ -351,7 +378,86 @@ class WS2812FX {
bool _requiresReset = false; bool _requiresReset = false;
} segment_runtime; } segment_runtime;
typedef struct ColorTransition { // 12 bytes
uint32_t colorOld = 0;
uint32_t transitionStart;
uint16_t transitionDur;
uint8_t segment = 0xFF; //lower 6 bits: the segment this transition is for (255 indicates transition not in use/available) upper 2 bits: color channel
uint8_t briOld = 0;
static void startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot) {
if (segn >= MAX_NUM_SEGMENTS || slot >= NUM_COLORS || dur == 0) return;
if (instance->_brightness == 0) return; //do not need transitions if master bri is off
uint8_t tIndex = 0xFF; //none found
uint16_t tProgression = 0;
uint8_t s = segn + (slot << 6); //merge slot and segment into one byte
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
uint8_t tSeg = instance->transitions[i].segment;
//see if this segment + color already has a running transition
if (tSeg == s) {
tIndex = i; break;
}
if (tSeg == 0xFF) { //free transition
tIndex = i; tProgression = 0xFFFF;
}
}
if (tIndex == 0xFF) { //no slot found yet
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
//find most progressed transition to overwrite
uint16_t prog = instance->transitions[i].progress();
if (prog > tProgression) {
tIndex = i; tProgression = prog;
}
}
}
ColorTransition& t = instance->transitions[tIndex];
if (t.segment == s) //this is an active transition on the same segment+color
{
t.briOld = t.currentBri();
t.colorOld = t.currentColor(oldCol);
} else {
t.briOld = oldBri;
t.colorOld = oldCol;
uint8_t prevSeg = t.segment & 0x3F;
if (prevSeg < MAX_NUM_SEGMENTS) instance->_segments[prevSeg].setOption(SEG_OPTION_TRANSITIONAL, false);
}
t.transitionDur = dur;
t.transitionStart = millis();
t.segment = s;
instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, true);
//refresh immediately, required for Solid mode
if (instance->_segment_runtimes[segn].next_time > t.transitionStart + 22) instance->_segment_runtimes[segn].next_time = t.transitionStart;
}
uint16_t progress(bool allowEnd = false) { //transition progression between 0-65535
uint32_t timeNow = millis();
if (timeNow - transitionStart > transitionDur) {
if (allowEnd) {
uint8_t segn = segment & 0x3F;
if (segn < MAX_NUM_SEGMENTS) instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, false);
segment = 0xFF;
}
return 0xFFFF;
}
uint32_t elapsed = timeNow - transitionStart;
uint32_t prog = elapsed * 0xFFFF / transitionDur;
return (prog > 0xFFFF) ? 0xFFFF : prog;
}
uint32_t currentColor(uint32_t colorNew) {
return instance->color_blend(colorOld, colorNew, progress(true), true);
}
uint8_t currentBri() {
uint8_t segn = segment & 0x3F;
if (segn >= MAX_NUM_SEGMENTS) return 0;
uint8_t briNew = instance->_segments[segn].opacity;
uint32_t prog = progress() + 1;
return ((briNew * prog) + (briOld * (0x10000 - prog))) >> 16;
}
} color_transition;
WS2812FX() { WS2812FX() {
WS2812FX::instance = this;
//assign each member of the _mode[] array to its respective function reference //assign each member of the _mode[] array to its respective function reference
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static; _mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink; _mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
@ -389,7 +495,7 @@ class WS2812FX {
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light; _mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random; _mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
_mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color; _mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color;
_mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue; _mode[FX_MODE_AURORA] = &WS2812FX::mode_aurora;
_mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random; _mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random;
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner; _mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet; _mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
@ -494,6 +600,7 @@ class WS2812FX {
setBrightness(uint8_t b), setBrightness(uint8_t b),
setRange(uint16_t i, uint16_t i2, uint32_t col), setRange(uint16_t i, uint16_t i2, uint32_t col),
setShowCallback(show_callback cb), setShowCallback(show_callback cb),
setTransition(uint16_t t),
setTransitionMode(bool t), setTransitionMode(bool t),
calcGammaTable(float), calcGammaTable(float),
trigger(void), trigger(void),
@ -548,7 +655,8 @@ class WS2812FX {
timebase, timebase,
color_wheel(uint8_t), color_wheel(uint8_t),
color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, 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,uint16_t,bool b16=false),
currentColor(uint32_t colorNew, uint8_t tNr),
gamma32(uint32_t), gamma32(uint32_t),
getLastShow(void), getLastShow(void),
getPixelColor(uint16_t), getPixelColor(uint16_t),
@ -603,7 +711,7 @@ class WS2812FX {
mode_colorful(void), mode_colorful(void),
mode_traffic_light(void), mode_traffic_light(void),
mode_running_color(void), mode_running_color(void),
mode_running_red_blue(void), mode_aurora(void),
mode_running_random(void), mode_running_random(void),
mode_larson_scanner(void), mode_larson_scanner(void),
mode_comet(void), mode_comet(void),
@ -696,7 +804,8 @@ class WS2812FX {
uint16_t _length, _lengthRaw, _virtualSegmentLength; uint16_t _length, _lengthRaw, _virtualSegmentLength;
uint16_t _rand16seed; uint16_t _rand16seed;
uint8_t _brightness; uint8_t _brightness;
static uint16_t _usedSegmentData; uint16_t _usedSegmentData = 0;
uint16_t _transitionDur = 750;
void load_gradient_palette(uint8_t); void load_gradient_palette(uint8_t);
void handle_palette(void); void handle_palette(void);
@ -736,11 +845,16 @@ class WS2812FX {
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);
void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend); void
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot);
uint32_t _lastPaletteChange = 0; uint32_t _lastPaletteChange = 0;
uint32_t _lastShow = 0; uint32_t _lastShow = 0;
uint32_t _colors_t[3];
uint8_t _bri_t;
#ifdef WLED_USE_ANALOG_LEDS #ifdef WLED_USE_ANALOG_LEDS
uint32_t _analogLastShow = 0; uint32_t _analogLastShow = 0;
RgbwColor _analogLastColor = 0; RgbwColor _analogLastColor = 0;
@ -756,7 +870,12 @@ class WS2812FX {
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
friend class Segment_runtime; friend class Segment_runtime;
uint16_t realPixelIndex(uint16_t i); ColorTransition transitions[MAX_NUM_TRANSITIONS]; //12 bytes per element
friend class ColorTransition;
uint16_t
realPixelIndex(uint16_t i),
transitionProgress(uint8_t tNr);
}; };
//10 names per line //10 names per line
@ -764,7 +883,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow", "Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd", "Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random", "Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream", "Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Aurora","Stream",
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All", "Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet", "Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise", "Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
@ -782,7 +901,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64", "Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn", "Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura", "Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
"Aurora","Atlantica","C9 2","C9 New","Temperature" "Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2"
])====="; ])=====";
#endif #endif

View File

@ -85,8 +85,8 @@ void WS2812FX::service() {
// segment's buffers are cleared // segment's buffers are cleared
SEGENV.resetIfRequired(); SEGENV.resetIfRequired();
if (SEGMENT.isActive()) if (!SEGMENT.isActive()) continue;
{
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
{ {
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
@ -95,6 +95,15 @@ void WS2812FX::service() {
if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
_virtualSegmentLength = SEGMENT.virtualLength(); _virtualSegmentLength = SEGMENT.virtualLength();
_bri_t = SEGMENT.opacity; _colors_t[0] = SEGMENT.colors[0]; _colors_t[1] = SEGMENT.colors[1]; _colors_t[2] = SEGMENT.colors[2];
if (!IS_SEGMENT_ON) _bri_t = 0;
for (uint8_t t = 0; t < MAX_NUM_TRANSITIONS; t++) {
if ((transitions[t].segment & 0x3F) != i) continue;
uint8_t slot = transitions[t].segment >> 6;
if (slot == 0) _bri_t = transitions[t].currentBri();
_colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]);
}
for (uint8_t c = 0; c < 3; c++) _colors_t[c] = gamma32(_colors_t[c]);
handle_palette(); handle_palette();
delay = (this->*_mode[SEGMENT.mode])(); //effect function delay = (this->*_mode[SEGMENT.mode])(); //effect function
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++; if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
@ -103,7 +112,6 @@ void WS2812FX::service() {
SEGENV.next_time = nowUp + delay; SEGENV.next_time = nowUp + delay;
} }
} }
}
_virtualSegmentLength = 0; _virtualSegmentLength = 0;
if(doShow) { if(doShow) {
yield(); yield();
@ -165,17 +173,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0; uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
if (SEGLEN) {//from segment if (SEGLEN) {//from segment
//color_blend(getpixel, col, SEGMENT.opacity); (pseudocode for future blending of segments) //color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
if (IS_SEGMENT_ON) if (_bri_t < 255) {
{ col.R = scale8(col.R, _bri_t);
if (SEGMENT.opacity < 255) { col.G = scale8(col.G, _bri_t);
col.R = scale8(col.R, SEGMENT.opacity); col.B = scale8(col.B, _bri_t);
col.G = scale8(col.G, SEGMENT.opacity); col.W = scale8(col.W, _bri_t);
col.B = scale8(col.B, SEGMENT.opacity);
col.W = scale8(col.W, SEGMENT.opacity);
}
} else {
col = BLACK;
} }
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */ /* Set all the pixels in the group, ensuring _skipFirstMode is honored */
@ -347,7 +350,7 @@ uint8_t WS2812FX::getPaletteCount()
return 13 + GRADIENT_PALETTE_COUNT; return 13 + GRADIENT_PALETTE_COUNT;
} }
//TODO transitions //TODO effect transitions
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) { bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
@ -394,12 +397,16 @@ void WS2812FX::setColor(uint8_t slot, uint32_t c) {
if (applyToAllSelected) { if (applyToAllSelected) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{ {
if (_segments[i].isSelected()) _segments[i].colors[slot] = c; if (_segments[i].isSelected()) {
_segments[i].setColor(slot, c, i);
applied = true;
}
} }
} }
if (!applyToAllSelected || !applied) { if (!applyToAllSelected || !applied) {
_segments[getMainSegmentId()].colors[slot] = c; uint8_t mainseg = getMainSegmentId();
_segments[mainseg].setColor(slot, c, mainseg);
} }
} }
@ -602,6 +609,11 @@ void WS2812FX::setShowCallback(show_callback cb)
_callback = cb; _callback = cb;
} }
void WS2812FX::setTransition(uint16_t t)
{
_transitionDur = t;
}
void WS2812FX::setTransitionMode(bool t) void WS2812FX::setTransitionMode(bool t)
{ {
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
@ -617,24 +629,26 @@ void WS2812FX::setTransitionMode(bool t)
/* /*
* color blend function * color blend function
*/ */
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) { uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
if(blend == 0) return color1; if(blend == 0) return color1;
if(blend == 255) return color2; uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
if(blend == blendmax) return color2;
uint8_t shift = b16 ? 16 : 8;
uint32_t w1 = (color1 >> 24) & 0xff; uint32_t w1 = (color1 >> 24) & 0xFF;
uint32_t r1 = (color1 >> 16) & 0xff; uint32_t r1 = (color1 >> 16) & 0xFF;
uint32_t g1 = (color1 >> 8) & 0xff; uint32_t g1 = (color1 >> 8) & 0xFF;
uint32_t b1 = color1 & 0xff; uint32_t b1 = color1 & 0xFF;
uint32_t w2 = (color2 >> 24) & 0xff; uint32_t w2 = (color2 >> 24) & 0xFF;
uint32_t r2 = (color2 >> 16) & 0xff; uint32_t r2 = (color2 >> 16) & 0xFF;
uint32_t g2 = (color2 >> 8) & 0xff; uint32_t g2 = (color2 >> 8) & 0xFF;
uint32_t b2 = color2 & 0xff; uint32_t b2 = color2 & 0xFF;
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8; uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8; uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8; uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8; uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3)); return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
} }
@ -1041,4 +1055,4 @@ uint32_t WS2812FX::gamma32(uint32_t color)
return ((w << 24) | (r << 16) | (g << 8) | (b)); return ((w << 24) | (r << 16) | (g << 8) | (b));
} }
uint16_t WS2812FX::_usedSegmentData = 0; WS2812FX* WS2812FX::instance = nullptr;

View File

@ -72,6 +72,11 @@ void deserializeConfig() {
CJSON(apBehavior, ap[F("behav")]); CJSON(apBehavior, ap[F("behav")]);
#ifdef WLED_USE_ETHERNET
JsonObject ethernet = doc[F("eth")];
CJSON(ethernetType, ethernet[F("type")]);
#endif
/* /*
JsonArray ap_ip = ap[F("ip")]; JsonArray ap_ip = ap[F("ip")];
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
@ -272,6 +277,7 @@ void deserializeConfig() {
CJSON(countdownMin, cntdwn_goal[4]); CJSON(countdownMin, cntdwn_goal[4]);
CJSON(countdownSec, cntdwn_goal[5]); CJSON(countdownSec, cntdwn_goal[5]);
CJSON(macroCountdown, cntdwn[F("macro")]); CJSON(macroCountdown, cntdwn[F("macro")]);
setCountdown();
JsonArray timers = tm[F("ins")]; JsonArray timers = tm[F("ins")];
uint8_t it = 0; uint8_t it = 0;
@ -382,6 +388,11 @@ void serializeConfig() {
wifi[F("sleep")] = !noWifiSleep; wifi[F("sleep")] = !noWifiSleep;
wifi[F("phy")] = 1; wifi[F("phy")] = 1;
#ifdef WLED_USE_ETHERNET
JsonObject ethernet = doc.createNestedObject("eth");
ethernet[F("type")] = ethernetType;
#endif
JsonObject hw = doc.createNestedObject("hw"); JsonObject hw = doc.createNestedObject("hw");
JsonObject hw_led = hw.createNestedObject("led"); JsonObject hw_led = hw.createNestedObject("led");

View File

@ -33,6 +33,11 @@ void colorFromUint24(uint32_t in, bool secondary)
} }
} }
//store color components in uint32_t
uint32_t colorFromRgbw(byte* rgbw) {
return (rgbw[0] << 16) + (rgbw[1] << 8) + rgbw[2] + (rgbw[3] << 24);
}
//relatively change white brightness, minumum A=5 //relatively change white brightness, minumum A=5
void relativeChangeWhite(int8_t amount, byte lowerBoundary) void relativeChangeWhite(int8_t amount, byte lowerBoundary)
{ {

View File

@ -132,6 +132,10 @@
#define BTN_TYPE_SWITCH 4 //not implemented #define BTN_TYPE_SWITCH 4 //not implemented
#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented #define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented
//Ethernet board types
#define WLED_ETH_NONE 0
#define WLED_ETH_WT32_ETH01 1
#define WLED_ETH_ESP32_POE 2
//Hue error codes //Hue error codes
#define HUE_ERROR_INACTIVE 0 #define HUE_ERROR_INACTIVE 0

View File

@ -454,9 +454,8 @@ function populateInfo(i)
else if (pwr > 0) {pwr = 50 * Math.round(pwr/50); pwru = pwr + " mA";} else if (pwr > 0) {pwr = 50 * Math.round(pwr/50); pwru = pwr + " mA";}
var urows=""; var urows="";
if (i.u) { if (i.u) {
for (var k = 0; k < i.u.length; k++) for (const [k, val] of Object.entries(i.u))
{ {
var val = i.u[k];
if (val[1]) { if (val[1]) {
urows += inforow(k,val[0],val[1]); urows += inforow(k,val[0],val[1]);
} else { } else {
@ -1335,10 +1334,13 @@ function lock(e) {
function move(e) { function move(e) {
if(!locked || pcMode) return; if(!locked || pcMode) return;
var dx = unify(e).clientX - x0, s = Math.sign(dx), var clientX = unify(e).clientX;
f = +(s*dx/w).toFixed(2); var dx = clientX - x0;
var s = Math.sign(dx);
var f = +(s*dx/w).toFixed(2);
if((iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) && if((clientX != 0) &&
(iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) &&
f > 0.12 && f > 0.12 &&
d.getElementsByClassName("tabcontent")[iSlide].scrollTop == scrollS) { d.getElementsByClassName("tabcontent")[iSlide].scrollTop == scrollS) {
_C.style.setProperty('--i', iSlide -= s); _C.style.setProperty('--i', iSlide -= s);

View File

@ -46,9 +46,9 @@
Enable ArduinoOTA: <input type="checkbox" name="AO"><br> Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
<h3>About</h3> <h3>About</h3>
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br> <a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br> <a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br> A huge thank you to everyone who helped me create WLED!<br><br>
(c) 2016-2020 Christian Schwinne <br> (c) 2016-2021 Christian Schwinne <br>
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br> <i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
Server message: <span class="sip"> Response error! </span><hr> Server message: <span class="sip"> Response error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button> <button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>

View File

@ -53,7 +53,7 @@ Type:
<div id=xp>Port: <input name="EP" type="number" min="1" max="65535" value="5568" class="d5" required><br></div> <div id=xp>Port: <input name="EP" type="number" min="1" max="65535" value="5568" class="d5" required><br></div>
Multicast: <input type="checkbox" name="EM"><br> Multicast: <input type="checkbox" name="EM"><br>
Start universe: <input name="EU" type="number" min="0" max="63999" required><br> Start universe: <input name="EU" type="number" min="0" max="63999" required><br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br> <i>Reboot required.</i> Check out <a href="https://github.com/LedFx/LedFx" target="_blank">LedFx</a>!<br>
Skip out-of-sequence packets: <input type="checkbox" name="ES"><br> Skip out-of-sequence packets: <input type="checkbox" name="ES"><br>
DMX start address: <input name="DA" type="number" min="0" max="510" required><br> DMX start address: <input name="DA" type="number" min="0" max="510" required><br>
DMX mode: DMX mode:

View File

@ -64,6 +64,12 @@
Disable WiFi sleep: <input type="checkbox" name="WS"><br> Disable WiFi sleep: <input type="checkbox" name="WS"><br>
<i>Can help with connectivity issues.<br> <i>Can help with connectivity issues.<br>
Do not enable if WiFi is working correctly, increases power consumption.</i> Do not enable if WiFi is working correctly, increases power consumption.</i>
<div id="ethd">
<h3>Ethernet Type</h3>
<select name="ETH">
<option value="0">None</option>
<option value="1">WT32-ETH01</option>
<option value="2">ESP32-POE</option></select><br><br></div>
<hr> <hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button> <button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
</form> </form>

View File

@ -34,6 +34,7 @@ void serializeConfigSec();
//colors.cpp //colors.cpp
void colorFromUint32(uint32_t in, bool secondary = false); void colorFromUint32(uint32_t in, bool secondary = false);
void colorFromUint24(uint32_t in, bool secondary = false); void colorFromUint24(uint32_t in, bool secondary = false);
uint32_t colorFromRgbw(byte* rgbw);
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0); void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
void colorKtoRGB(uint16_t kelvin, byte* rgb); void colorKtoRGB(uint16_t kelvin, byte* rgb);
@ -109,7 +110,7 @@ void setValuesFromMainSeg();
void resetTimebase(); void resetTimebase();
void toggleOnOff(); void toggleOnOff();
void setAllLeds(); void setAllLeds();
void setLedsStandard(bool justColors = false); void setLedsStandard();
bool colorChanged(); bool colorChanged();
void colorUpdated(int callMode); void colorUpdated(int callMode);
void updateInterfaces(uint8_t callMode); void updateInterfaces(uint8_t callMode);

View File

@ -61,9 +61,11 @@ value="2">Always</option><option value="3">Never (not recommended)</option>
</select><br>AP IP: <span class="sip">Not active</span><br><h3>Experimental</h3> </select><br>AP IP: <span class="sip">Not active</span><br><h3>Experimental</h3>
Disable WiFi sleep: <input type="checkbox" name="WS"><br><i> Disable WiFi sleep: <input type="checkbox" name="WS"><br><i>
Can help with connectivity issues.<br> Can help with connectivity issues.<br>
Do not enable if WiFi is working correctly, increases power consumption.</i><hr> Do not enable if WiFi is working correctly, increases power consumption.</i><div
<button type="button" onclick="B()">Back</button><button type="submit"> id="ethd"><h3>Ethernet Type</h3><select name="ETH"><option value="0">None
Save & Connect</button></form></body></html>)====="; </option><option value="1">WT32-ETH01</option><option value="2">ESP32-POE
</option></select><br><br></div><hr><button type="button" onclick="B()">Back
</button><button type="submit">Save & Connect</button></form></body></html>)=====";
// Autogenerated from wled00/data/settings_leds.htm, do not edit!! // Autogenerated from wled00/data/settings_leds.htm, do not edit!!
@ -236,7 +238,7 @@ Reboot required to apply changes.</i><h3>Realtime</h3>Receive UDP realtime:
id="xp">Port: <input name="EP" type="number" min="1" max="65535" value="5568" id="xp">Port: <input name="EP" type="number" min="1" max="65535" value="5568"
class="d5" required><br></div>Multicast: <input type="checkbox" name="EM"><br> class="d5" required><br></div>Multicast: <input type="checkbox" name="EM"><br>
Start universe: <input name="EU" type="number" min="0" max="63999" required><br> Start universe: <input name="EU" type="number" min="0" max="63999" required><br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" <i>Reboot required.</i> Check out <a href="https://github.com/LedFx/LedFx"
target="_blank">LedFx</a>!<br>Skip out-of-sequence packets: <input target="_blank">LedFx</a>!<br>Skip out-of-sequence packets: <input
type="checkbox" name="ES"><br>DMX start address: <input name="DA" type="number" type="checkbox" name="ES"><br>DMX start address: <input name="DA" type="number"
min="0" max="510" required><br>DMX mode: <select name="DM"><option value="0"> min="0" max="510" required><br>DMX mode: <select name="DM"><option value="0">
@ -364,10 +366,10 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
</button><br>Enable ArduinoOTA: <input type="checkbox" name="AO"><br><h3>About </button><br>Enable ArduinoOTA: <input type="checkbox" name="AO"><br><h3>About
</h3><a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> </h3><a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a>
version 0.11.1<br><br><a version 0.11.1<br><br><a
href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits"
target="_blank">Contributors, dependencies and special thanks</a><br> target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br> A huge thank you to everyone who helped me create WLED!<br><br>
(c) 2016-2020 Christian Schwinne<br><i>Licensed under the <a (c) 2016-2021 Christian Schwinne<br><i>Licensed under the <a
href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank"> href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">
MIT license</a></i><br><br>Server message: <span class="sip">Response error! MIT license</a></i><br><br>Server message: <span class="sip">Response error!
</span><hr><button type="button" onclick="B()">Back</button><button </span><hr><button type="button" onclick="B()">Back</button><button

File diff suppressed because it is too large Load Diff

View File

@ -23,13 +23,13 @@ void deserializeSegment(JsonObject elem, byte it)
int segbri = elem["bri"] | -1; int segbri = elem["bri"] | -1;
if (segbri == 0) { if (segbri == 0) {
seg.setOption(SEG_OPTION_ON, 0); seg.setOption(SEG_OPTION_ON, 0, id);
} else if (segbri > 0) { } else if (segbri > 0) {
seg.opacity = segbri; seg.setOpacity(segbri, id);
seg.setOption(SEG_OPTION_ON, 1); seg.setOption(SEG_OPTION_ON, 1, id);
} }
seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON)); seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON), id);
JsonArray colarr = elem[F("col")]; JsonArray colarr = elem[F("col")];
if (!colarr.isNull()) if (!colarr.isNull())
@ -45,7 +45,7 @@ void deserializeSegment(JsonObject elem, byte it)
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400 if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
int kelvin = colarr[i] | -1; int kelvin = colarr[i] | -1;
if (kelvin < 0) continue; if (kelvin < 0) continue;
if (kelvin == 0) seg.colors[i] = 0; if (kelvin == 0) seg.setColor(i, 0, id);
if (kelvin > 0) colorKtoRGB(kelvin, brgbw); if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
colValid = true; colValid = true;
} else { //HEX string, e.g. "FFAA00" } else { //HEX string, e.g. "FFAA00"
@ -57,7 +57,7 @@ void deserializeSegment(JsonObject elem, byte it)
if (sz == 0) continue; //do nothing on empty array if (sz == 0) continue; //do nothing on empty array
byte cp = copyArray(colX, rgbw, 4); byte cp = copyArray(colX, rgbw, 4);
if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0; if (cp == 1 && rgbw[0] == 0) seg.setColor(i, 0, id);
colValid = true; colValid = true;
} }
@ -66,8 +66,8 @@ void deserializeSegment(JsonObject elem, byte it)
{ {
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];} if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];} if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
} else { //normal case, apply directly to segment (=> no transition!) } else { //normal case, apply directly to segment
seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))); seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
} }
} }
@ -168,6 +168,7 @@ bool deserializeState(JsonObject root)
{ {
transitionDelay = tr; transitionDelay = tr;
transitionDelay *= 100; transitionDelay *= 100;
transitionDelayTemp = transitionDelay;
} }
tr = root[F("tt")] | -1; tr = root[F("tt")] | -1;
@ -177,6 +178,7 @@ bool deserializeState(JsonObject root)
transitionDelayTemp *= 100; transitionDelayTemp *= 100;
jsonTransitionOnce = true; jsonTransitionOnce = true;
} }
strip.setTransition(transitionDelayTemp);
int cy = root[F("pl")] | -2; int cy = root[F("pl")] | -2;
if (cy > -2) presetCyclingEnabled = (cy >= 0); if (cy > -2) presetCyclingEnabled = (cy >= 0);

View File

@ -51,24 +51,20 @@ void setAllLeds() {
} }
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY)
{ {
colorRGBtoRGBW(colT); colorRGBtoRGBW(col);
colorRGBtoRGBW(colSecT); colorRGBtoRGBW(colSec);
}
strip.setColor(0, col[0], col[1], col[2], col[3]);
strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY)
{
col[3] = 0; colSec[3] = 0;
} }
strip.setColor(0, colT[0], colT[1], colT[2], colT[3]);
strip.setColor(1, colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
} }
void setLedsStandard(bool justColors) void setLedsStandard()
{ {
for (byte i=0; i<4; i++)
{
colOld[i] = col[i];
colT[i] = col[i];
colSecOld[i] = colSec[i];
colSecT[i] = colSec[i];
}
if (justColors) return;
briOld = bri; briOld = bri;
briT = bri; briT = bri;
setAllLeds(); setAllLeds();
@ -145,7 +141,7 @@ void colorUpdated(int callMode)
} }
if (briT == 0) if (briT == 0)
{ {
setLedsStandard(true); //do not color transition if starting from off //setLedsStandard(true); //do not color transition if starting from off!
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
} }
@ -160,15 +156,11 @@ void colorUpdated(int callMode)
//set correct delay if not using notification delay //set correct delay if not using notification delay
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay; if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
jsonTransitionOnce = false; jsonTransitionOnce = false;
strip.setTransition(transitionDelayTemp);
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;} if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
if (transitionActive) if (transitionActive)
{ {
for (byte i=0; i<4; i++)
{
colOld[i] = colT[i];
colSecOld[i] = colSecT[i];
}
briOld = briT; briOld = briT;
tperLast = 0; tperLast = 0;
} }
@ -177,6 +169,7 @@ void colorUpdated(int callMode)
transitionStartTime = millis(); transitionStartTime = millis();
} else } else
{ {
strip.setTransition(0);
setLedsStandard(); setLedsStandard();
strip.trigger(); strip.trigger();
} }
@ -222,11 +215,6 @@ void handleTransitions()
} }
if (tper - tperLast < 0.004) return; if (tper - tperLast < 0.004) return;
tperLast = tper; tperLast = tper;
for (byte i=0; i<4; i++)
{
colT[i] = colOld[i]+((col[i] - colOld[i])*tper);
colSecT[i] = colSecOld[i]+((colSec[i] - colSecOld[i])*tper);
}
briT = briOld +((bri - briOld )*tper); briT = briOld +((bri - briOld )*tper);
setAllLeds(); setAllLeds();

View File

@ -70,7 +70,7 @@ void parseLxJson(int lxValue, byte segId, bool secondary)
} else { } else {
DEBUG_PRINT(F("LX: segment ")); DEBUG_PRINT(F("LX: segment "));
DEBUG_PRINTLN(segId); DEBUG_PRINTLN(segId);
strip.getSegment(segId).colors[secondary] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))); strip.getSegment(segId).setColor(secondary, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), segId);
} }
} }
} }

View File

@ -244,7 +244,7 @@ bool checkCountdown()
if (countdownMode) localTime = n - countdownTime + utcOffsetSecs; if (countdownMode) localTime = n - countdownTime + utcOffsetSecs;
if (!countdownOverTriggered) if (!countdownOverTriggered)
{ {
if (macroCountdown != 0) applyMacro(macroCountdown); if (macroCountdown != 0) applyPreset(macroCountdown);
countdownOverTriggered = true; countdownOverTriggered = true;
return true; return true;
} }

View File

@ -13,7 +13,7 @@
#ifndef PalettesWLED_h #ifndef PalettesWLED_h
#define PalettesWLED_h #define PalettesWLED_h
#define GRADIENT_PALETTE_COUNT 42 #define GRADIENT_PALETTE_COUNT 43
const byte ib_jul01_gp[] PROGMEM = { const byte ib_jul01_gp[] PROGMEM = {
0, 194, 1, 1, 0, 194, 1, 1,
@ -631,6 +631,14 @@ const byte temperature_gp[] PROGMEM = {
240, 80, 3, 3, 240, 80, 3, 3,
255, 80, 3, 3}; 255, 80, 3, 3};
const byte Aurora2[] PROGMEM = {
0, 17, 177, 13, //Greenish
64, 121, 242, 5, //Greenish
128, 25, 173, 121, //Turquoise
192, 250, 77, 127, //Pink
255, 171, 101, 221 //Purple
};
// Single array of defined cpt-city color palettes. // Single array of defined cpt-city color palettes.
// This will let us programmatically choose one based on // This will let us programmatically choose one based on
// a number, rather than having to activate each explicitly // a number, rather than having to activate each explicitly
@ -677,7 +685,8 @@ const byte* const gGradientPalettes[] PROGMEM = {
Atlantica_gp, //51-38 Atlantica Atlantica_gp, //51-38 Atlantica
C9_2_gp, //52-39 C9 2 C9_2_gp, //52-39 C9 2
C9_new_gp, //53-40 C9 New C9_new_gp, //53-40 C9 New
temperature_gp //54-41 Temperature temperature_gp, //54-41 Temperature
Aurora2 //55-42 Aurora 2
}; };
#endif #endif

View File

@ -6,6 +6,7 @@
bool applyPreset(byte index) bool applyPreset(byte index)
{ {
if (index == 0) return false;
if (fileDoc) { if (fileDoc) {
errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD; errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
JsonObject fdo = fileDoc->as<JsonObject>(); JsonObject fdo = fileDoc->as<JsonObject>();

View File

@ -52,6 +52,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
noWifiSleep = request->hasArg(F("WS")); noWifiSleep = request->hasArg(F("WS"));
#ifdef WLED_USE_ETHERNET
ethernetType = request->arg(F("ETH")).toInt();
#endif
char k[3]; k[2] = 0; char k[3]; k[2] = 0;
for (int i = 0; i<4; i++) for (int i = 0; i<4; i++)
{ {
@ -90,7 +94,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
saveCurrPresetCycConf = request->hasArg(F("PC")); saveCurrPresetCycConf = request->hasArg(F("PC"));
turnOnAtBoot = request->hasArg(F("BO")); turnOnAtBoot = request->hasArg(F("BO"));
t = request->arg(F("BP")).toInt(); t = request->arg(F("BP")).toInt();
if (t <= 25) bootPreset = t; if (t <= 250) bootPreset = t;
strip.gammaCorrectBri = request->hasArg(F("GB")); strip.gammaCorrectBri = request->hasArg(F("GB"));
strip.gammaCorrectCol = request->hasArg(F("GC")); strip.gammaCorrectCol = request->hasArg(F("GC"));
@ -236,6 +240,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
countdownHour = request->arg(F("CH")).toInt(); countdownHour = request->arg(F("CH")).toInt();
countdownMin = request->arg(F("CM")).toInt(); countdownMin = request->arg(F("CM")).toInt();
countdownSec = request->arg(F("CS")).toInt(); countdownSec = request->arg(F("CS")).toInt();
setCountdown();
macroAlexaOn = request->arg(F("A0")).toInt(); macroAlexaOn = request->arg(F("A0")).toInt();
macroAlexaOff = request->arg(F("A1")).toInt(); macroAlexaOff = request->arg(F("A1")).toInt();
@ -380,7 +385,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
DEBUG_PRINT(F("API req: ")); DEBUG_PRINT(F("API req: "));
DEBUG_PRINTLN(req); DEBUG_PRINTLN(req);
strip.applyToAllSelected = true; strip.applyToAllSelected = false;
//snapshot to check if request changed values later, temporary.
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
byte prevEffect = effectCurrent;
byte prevSpeed = effectSpeed;
byte prevIntensity = effectIntensity;
byte prevPalette = effectPalette;
//segment select (sets main segment) //segment select (sets main segment)
byte prevMain = strip.getMainSegmentId(); byte prevMain = strip.getMainSegmentId();
@ -388,16 +400,16 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (pos > 0) { if (pos > 0) {
strip.mainSegment = getNumVal(&req, pos); strip.mainSegment = getNumVal(&req, pos);
} }
byte main = strip.getMainSegmentId(); byte selectedSeg = strip.getMainSegmentId();
if (main != prevMain) setValuesFromMainSeg(); if (selectedSeg != prevMain) setValuesFromMainSeg();
pos = req.indexOf(F("SS=")); pos = req.indexOf(F("SS="));
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); byte t = getNumVal(&req, pos);
if (t < strip.getMaxSegments()) main = t; if (t < strip.getMaxSegments()) selectedSeg = t;
} }
WS2812FX::Segment& mainseg = strip.getSegment(main); WS2812FX::Segment& mainseg = strip.getSegment(selectedSeg);
pos = req.indexOf(F("SV=")); //segment selected pos = req.indexOf(F("SV=")); //segment selected
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); byte t = getNumVal(&req, pos);
@ -431,9 +443,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (pos > 0) { if (pos > 0) {
spcI = getNumVal(&req, pos); spcI = getNumVal(&req, pos);
} }
strip.setSegment(main, startI, stopI, grpI, spcI); strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
main = strip.getMainSegmentId();
//set presets //set presets
pos = req.indexOf(F("P1=")); //sets first preset for cycle pos = req.indexOf(F("P1=")); //sets first preset for cycle
@ -531,7 +541,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (pos > 0) { if (pos > 0) {
byte t[4]; byte t[4];
colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str()); colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str());
if (selectedSeg != strip.getMainSegmentId()) {
strip.applyToAllSelected = true;
strip.setColor(2, t[0], t[1], t[2], t[3]); strip.setColor(2, t[0], t[1], t[2], t[3]);
} else {
strip.getSegment(selectedSeg).setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg);
}
} }
//set to random hue SR=0->1st SR=1->2nd //set to random hue SR=0->1st SR=1->2nd
@ -646,19 +661,19 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//Segment reverse //Segment reverse
pos = req.indexOf(F("RV=")); pos = req.indexOf(F("RV="));
if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0'); if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
//Segment reverse //Segment reverse
pos = req.indexOf(F("MI=")); pos = req.indexOf(F("MI="));
if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0'); if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
//Segment brightness/opacity //Segment brightness/opacity
pos = req.indexOf(F("SB=")); pos = req.indexOf(F("SB="));
if (pos > 0) { if (pos > 0) {
byte segbri = getNumVal(&req, pos); byte segbri = getNumVal(&req, pos);
strip.getSegment(main).setOption(SEG_OPTION_ON, segbri); strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri, selectedSeg);
if (segbri) { if (segbri) {
strip.getSegment(main).opacity = segbri; strip.getSegment(selectedSeg).setOpacity(segbri, selectedSeg);
} }
} }
@ -715,12 +730,44 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
} }
//you can add more if you need //you can add more if you need
//apply to all selected manually to prevent #1618. Temporary
bool col0Changed = false, col1Changed = false;
for (uint8_t i = 0; i < 4; i++) {
if (col[i] != prevCol[i]) col0Changed = true;
if (colSec[i] != prevColSec[i]) col1Changed = true;
}
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
{
WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isSelected()) continue;
if (effectCurrent != prevEffect) seg.mode = effectCurrent;
if (effectSpeed != prevSpeed) seg.speed = effectSpeed;
if (effectIntensity != prevIntensity) seg.intensity = effectIntensity;
if (effectPalette != prevPalette) seg.palette = effectPalette;
}
if (col0Changed) {
if (selectedSeg == strip.getMainSegmentId()) {
strip.applyToAllSelected = true;
strip.setColor(0, colorFromRgbw(col));
}
}
if (col1Changed) {
if (selectedSeg == strip.getMainSegmentId()) {
strip.applyToAllSelected = true;
strip.setColor(1, colorFromRgbw(colSec));
}
}
//end of temporary fix code
if (!apply) return true; //when called by JSON API, do not call colorUpdated() here if (!apply) return true; //when called by JSON API, do not call colorUpdated() here
//internal call, does not send XML response //internal call, does not send XML response
pos = req.indexOf(F("IN")); pos = req.indexOf(F("IN"));
if (pos < 1) XML_response(request); if (pos < 1) XML_response(request);
strip.applyToAllSelected = false;
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
colorUpdated((pos > 0) ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated((pos > 0) ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);

View File

@ -19,6 +19,9 @@
#ifdef USERMOD_BUZZER #ifdef USERMOD_BUZZER
#include "../usermods/buzzer/usermod_v2_buzzer.h" #include "../usermods/buzzer/usermod_v2_buzzer.h"
#endif #endif
#ifdef USERMOD_SENSORSTOMQTT
#include "usermod_v2_SensorsToMqtt.h"
#endif
// BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h // BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h
#ifdef USERMOD_BME280 #ifdef USERMOD_BME280
@ -27,7 +30,7 @@
void registerUsermods() void registerUsermods()
{ {
/* /*
* Add your usermod class name here * Add your usermod class name here
* || || || * || || ||
* \/ \/ \/ * \/ \/ \/

View File

@ -10,6 +10,49 @@ WLED::WLED()
{ {
} }
#ifdef WLED_USE_ETHERNET
// settings for various ethernet boards
typedef struct EthernetSettings {
uint8_t eth_address;
int eth_power;
int eth_mdc;
int eth_mdio;
eth_phy_type_t eth_type;
eth_clock_mode_t eth_clk_mode;
} ethernet_settings;
ethernet_settings ethernetBoards[] = {
// None
{
},
// WT32-EHT01
// Please note, from my testing only these pins work for LED outputs:
// IO2, IO4, IO12, IO14, IO15
// These pins do not appear to work from my testing:
// IO35, IO36, IO39
{
1, // eth_address,
16, // eth_power,
23, // eth_mdc,
18, // eth_mdio,
ETH_PHY_LAN8720, // eth_type,
ETH_CLOCK_GPIO0_IN // eth_clk_mode
},
// ESP32-POE
{
0, // eth_address,
12, // eth_power,
23, // eth_mdc,
18, // eth_mdio,
ETH_PHY_LAN8720, // eth_type,
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
}
};
#endif
// turns all LEDs off and restarts ESP // turns all LEDs off and restarts ESP
void WLED::reset() void WLED::reset()
{ {
@ -393,7 +436,18 @@ void WLED::initConnection()
#endif #endif
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
ETH.begin(); // Only initialize ethernet board if not NONE
if (ethernetType != WLED_ETH_NONE) {
ethernet_settings es = ethernetBoards[ethernetType];
ETH.begin(
(uint8_t) es.eth_address,
(int) es.eth_power,
(int) es.eth_mdc,
(int) es.eth_mdio,
(eth_phy_type_t) es.eth_type,
(eth_clock_mode_t) es.eth_clk_mode
);
}
#endif #endif
WiFi.disconnect(true); // close old connections WiFi.disconnect(true); // close old connections

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2012210 #define VERSION 2101130
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -204,6 +204,9 @@ WLED_GLOBAL IPAddress staticIP _INIT_N((( 0, 0, 0, 0))); // static IP
WLED_GLOBAL IPAddress staticGateway _INIT_N((( 0, 0, 0, 0))); // gateway (router) IP WLED_GLOBAL IPAddress staticGateway _INIT_N((( 0, 0, 0, 0))); // gateway (router) IP
WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks
WLED_GLOBAL bool noWifiSleep _INIT(false); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues WLED_GLOBAL bool noWifiSleep _INIT(false); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues
#ifdef WLED_USE_ETHERNET
WLED_GLOBAL int ethernetType _INIT(WLED_ETH_ESP32_POE); // ethernet board type
#endif
// LED CONFIG // LED CONFIG
WLED_GLOBAL uint16_t ledCount _INIT(30); // overcurrent prevented by ABL WLED_GLOBAL uint16_t ledCount _INIT(30); // overcurrent prevented by ABL
@ -342,11 +345,7 @@ WLED_GLOBAL bool interfacesInited _INIT(false);
WLED_GLOBAL bool wasConnected _INIT(false); WLED_GLOBAL bool wasConnected _INIT(false);
// color // color
WLED_GLOBAL byte colOld[] _INIT_N(({ 0, 0, 0, 0 })); // color before transition
WLED_GLOBAL byte colT[] _INIT_N(({ 0, 0, 0, 0 })); // color that is currently displayed on the LEDs
WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs
WLED_GLOBAL byte colSecT[] _INIT_N(({ 0, 0, 0, 0 }));
WLED_GLOBAL byte colSecOld[] _INIT_N(({ 0, 0, 0, 0 }));
WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 })); WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 }));
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same

View File

@ -219,6 +219,12 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("AC"),apChannel); sappend('v',SET_F("AC"),apChannel);
sappend('c',SET_F("WS"),noWifiSleep); sappend('c',SET_F("WS"),noWifiSleep);
#ifdef WLED_USE_ETHERNET
sappend('i',SET_F("ETH"),ethernetType);
#else
//hide ethernet setting if not compiled in
oappend(SET_F("document.getElementById('ethd').style.display='none';"));
#endif
if (Network.isConnected()) //is connected if (Network.isConnected()) //is connected
{ {