Merge branch 'master' into dev

Conflicts:
	CHANGELOG.md
	package.json
	platformio.ini
	usermods/Temperature/usermod_temperature.h
	wled00/FX.cpp
	wled00/FX.h
	wled00/FX_fcn.cpp
	wled00/cfg.cpp
	wled00/data/index.js
	wled00/data/settings_leds.htm
	wled00/data/settings_time.htm
	wled00/data/style.css
	wled00/html_other.h
	wled00/html_settings.h
	wled00/html_ui.h
	wled00/ntp.cpp
	wled00/usermods_list.cpp
	wled00/wled.cpp
	wled00/wled.h
This commit is contained in:
Blaz Kristan 2021-04-14 18:19:51 +02:00
commit 29e048af7b
29 changed files with 1179 additions and 886 deletions

View File

@ -2,11 +2,30 @@
### Builds after release 0.12.0
#### Build 2104141
- Reduced memory usage by 540b by switching to a different trigonometric approximation
#### Build 2104140
- Added dynamic location-based Sunrise/Sunset macros (PR #1889)
- Improved seasonal background handling (PR #1890)
- Fixed instance discovery not working if MQTT not compiled in
- Fixed Button, IR, Relay pin not assigned by default (resolves #1891)
#### Build 2104120
- Added switch support (button macro is switch closing action, long press macro switch opening)
- Replaced Circus effect with new Running Dual effect (Circus is Tricolor Chase with Red/White/Black)
- Fixed ledmap with multiple segments (PR #1864)
#### Build 2104030
- Fixed ESP32 crash on Drip effect with reversed segment (#1854)
- Added flag `WLED_DISABLE_BROWNOUT_DET` to disable ESP32 brownout detector (off by default)
### WLED release 0.12.0
#### Build 2104020
- Allow clearing button/IR/relay pin on platforms that don't support negative numbers

View File

@ -178,7 +178,7 @@ upload_speed = 115200
lib_compat_mode = strict
lib_deps =
fastled/FastLED @ 3.3.2
NeoPixelBus @ 2.6.0
NeoPixelBus @ ^2.6.0
ESPAsyncTCP @ 1.2.0
ESPAsyncUDP
AsyncTCP @ 1.0.3
@ -188,10 +188,10 @@ lib_deps =
#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
#U8g2@~2.27.2
U8g2@~2.27.2
#For Dallas sensor uncomment following 2 lines
#OneWire@~2.3.5
#milesburton/DallasTemperature@^3.9.0
OneWire@~2.3.5
milesburton/DallasTemperature@^3.9.0
#For BME280 sensor uncomment following
#BME280@~3.0.0
; adafruit/Adafruit BMP280 Library @ 2.1.0
@ -400,31 +400,7 @@ build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_f
# codm pixel controller board configurations
# ------------------------------------------------------------------------------
[env:codm-controller-0.4]
board = esp_wroom_02
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
[env:codm-controller-0.4-WS2801]
board = esp_wroom_02
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.4-APA102]
board = esp_wroom_02
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_APA102 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.5]
[env:codm-controller-0.6]
board = esp_wroom_02
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
@ -432,18 +408,10 @@ board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266}
[env:codm-controller-0.5-WS2801]
[env:codm-controller-0.6-rev2]
board = esp_wroom_02
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 #-D CLKPIN=0 -D DATAPIN=2
[env:codm-controller-0.5-APA102]
board = esp_wroom_02
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_APA102 #-D CLKPIN=0 -D DATAPIN=2
build_flags = ${common.build_flags_esp8266}

6
tools/WLED_ESP32_8MB.csv Normal file
View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x200000,
app1, app, ota_1, 0x210000,0x200000,
spiffs, data, spiffs, 0x410000,0x3F0000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x200000
5 app1 app ota_1 0x210000 0x200000
6 spiffs data spiffs 0x410000 0x3F0000

View File

@ -93,8 +93,8 @@ or remove them and put everything on one line.
| segment-delay-ms | Delay (milliseconds) between switching on/off each step | 150 |
| on-time-s | Time (seconds) the stairs stay lit after last detection | 5 |
| bottom-echo-us | Detection range of ultrasonic sensor | 1749 |
| bottomsensor | Manually trigger a down to up animation via API | false |
| topsensor | Manually trigger an up to down animation via API | false |
| bottom-sensor | Manually trigger a down to up animation via API | false |
| top-sensor | Manually trigger an up to down animation via API | false |
To read the current settings, open a browser to `http://xxx.xxx.xxx.xxx/json/state` (use your WLED
@ -108,8 +108,8 @@ The staircase settings and sensor states are inside the WLED status element:
"enabled": true,
"segment-delay-ms": 150,
"on-time-s": 5,
"bottomsensor": false,
"topsensor": false
"bottom-sensor": false,
"tops-ensor": false
},
}
```
@ -187,7 +187,7 @@ the API. To simulate triggering the bottom sensor, use:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"staircase":{"bottomsensor":true}}' \
-d '{"staircase":{"bottom-sensor":true}}' \
xxx.xxx.xxx.xxx/json/state
```
@ -195,7 +195,7 @@ Likewise, to trigger the top sensor, use:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"staircase":{"topsensor":true}}' \
-d '{"staircase":{"top-sensor":true}}' \
xxx.xxx.xxx.xxx/json/state
```

View File

@ -12,10 +12,11 @@ private:
// User-defined configuration
#define Celsius // Show temperature mesaurement in Celcius. Comment out for Fahrenheit
#define TemperatureDecimals 1 // Number of decimal places in published temperaure values
#define HumidityDecimals 0 // Number of decimal places in published humidity values
#define HumidityDecimals 2 // Number of decimal places in published humidity values
#define PressureDecimals 2 // Number of decimal places in published pressure values
#define TemperatureInterval 5 // Interval to measure temperature (and humidity, dew point if available) in seconds
#define PressureInterval 300 // Interval to measure pressure in seconds
#define PublishAlways 0 // Publish values even when they have not changed
// Sanity checks
#if !defined(TemperatureDecimals) || TemperatureDecimals < 0
@ -33,6 +34,9 @@ private:
#if !defined(PressureInterval) || PressureInterval < 0
#define PressureInterval TemperatureInterval
#endif
#if !defined(PublishAlways)
#define PublishAlways 0
#endif
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
uint8_t SCL_PIN = 22;
@ -58,7 +62,7 @@ private:
BME280I2C bme{settings};
uint8_t SensorType;
uint8_t sensorType;
// Measurement timers
long timer;
@ -66,11 +70,11 @@ private:
long lastPressureMeasure = 0;
// Current sensor values
float SensorTemperature;
float SensorHumidity;
float SensorHeatIndex;
float SensorDewPoint;
float SensorPressure;
float sensorTemperature;
float sensorHumidity;
float sensorHeatIndex;
float sensorDewPoint;
float sensorPressure;
// Track previous sensor values
float lastTemperature;
float lastHumidity;
@ -96,13 +100,13 @@ private:
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
SensorTemperature = _temperature;
SensorHumidity = _humidity;
SensorPressure = _pressure;
if (SensorType == 1)
sensorTemperature = _temperature;
sensorHumidity = _humidity;
sensorPressure = _pressure;
if (sensorType == 1)
{
SensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
SensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
}
}
@ -113,7 +117,7 @@ public:
if (!bme.begin())
{
SensorType = 0;
sensorType = 0;
Serial.println("Could not find BME280I2C sensor!");
}
else
@ -121,15 +125,15 @@ public:
switch (bme.chipModel())
{
case BME280::ChipModel_BME280:
SensorType = 1;
sensorType = 1;
Serial.println("Found BME280 sensor! Success.");
break;
case BME280::ChipModel_BMP280:
SensorType = 2;
sensorType = 2;
Serial.println("Found BMP280 sensor! No Humidity available.");
break;
default:
SensorType = 0;
sensorType = 0;
Serial.println("Found UNKNOWN sensor! Error!");
}
}
@ -139,7 +143,7 @@ public:
{
// BME280 sensor MQTT publishing
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
if (SensorType != 0 && mqtt != nullptr)
if (sensorType != 0 && mqtt != nullptr)
{
// Timer to fetch new temperature, humidity and pressure data at intervals
timer = millis();
@ -148,48 +152,48 @@ public:
{
lastTemperatureMeasure = timer;
UpdateBME280Data(SensorType);
UpdateBME280Data(sensorType);
float Temperature = roundf(SensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
float Humidity, HeatIndex, DewPoint;
float temperature = roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
float humidity, heatIndex, dewPoint;
// If temperature has changed since last measure, create string populated with device topic
// from the UI and values read from sensor, then publish to broker
if (Temperature != lastTemperature)
if (temperature != lastTemperature || PublishAlways)
{
String topic = String(mqttDeviceTopic) + "/temperature";
mqttTemperaturePub = mqtt->publish(topic.c_str(), 0, false, String(Temperature, TemperatureDecimals).c_str());
mqttTemperaturePub = mqtt->publish(topic.c_str(), 0, false, String(temperature, TemperatureDecimals).c_str());
}
lastTemperature = Temperature; // Update last sensor temperature for next loop
lastTemperature = temperature; // Update last sensor temperature for next loop
if (SensorType == 1) // Only if sensor is a BME280
if (sensorType == 1) // Only if sensor is a BME280
{
Humidity = roundf(SensorHumidity * pow(10, HumidityDecimals)) / pow(10, HumidityDecimals);
HeatIndex = roundf(SensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
DewPoint = roundf(SensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
humidity = roundf(sensorHumidity * pow(10, HumidityDecimals)) / pow(10, HumidityDecimals);
heatIndex = roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
dewPoint = roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
if (Humidity != lastHumidity)
if (humidity != lastHumidity || PublishAlways)
{
String topic = String(mqttDeviceTopic) + "/humidity";
mqtt->publish(topic.c_str(), 0, false, String(Humidity, HumidityDecimals).c_str());
mqtt->publish(topic.c_str(), 0, false, String(humidity, HumidityDecimals).c_str());
}
if (HeatIndex != lastHeatIndex)
if (heatIndex != lastHeatIndex || PublishAlways)
{
String topic = String(mqttDeviceTopic) + "/heat_index";
mqtt->publish(topic.c_str(), 0, false, String(HeatIndex, TemperatureDecimals).c_str());
mqtt->publish(topic.c_str(), 0, false, String(heatIndex, TemperatureDecimals).c_str());
}
if (DewPoint != lastDewPoint)
if (dewPoint != lastDewPoint || PublishAlways)
{
String topic = String(mqttDeviceTopic) + "/dew_point";
mqtt->publish(topic.c_str(), 0, false, String(DewPoint, TemperatureDecimals).c_str());
mqtt->publish(topic.c_str(), 0, false, String(dewPoint, TemperatureDecimals).c_str());
}
lastHumidity = Humidity;
lastHeatIndex = HeatIndex;
lastDewPoint = DewPoint;
lastHumidity = humidity;
lastHeatIndex = heatIndex;
lastDewPoint = dewPoint;
}
}
@ -197,15 +201,15 @@ public:
{
lastPressureMeasure = timer;
float Pressure = roundf(SensorPressure * pow(10, PressureDecimals)) / pow(10, PressureDecimals);
float pressure = roundf(sensorPressure * pow(10, PressureDecimals)) / pow(10, PressureDecimals);
if (Pressure != lastPressure)
if (pressure != lastPressure || PublishAlways)
{
String topic = String(mqttDeviceTopic) + "/pressure";
mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(Pressure, PressureDecimals).c_str());
mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(pressure, PressureDecimals).c_str());
}
lastPressure = Pressure;
lastPressure = pressure;
}
}
}

View File

@ -39,7 +39,7 @@ default_envs = d1_mini
...
[common]
...
lib_deps_external =
lib_deps =
...
#For use SSD1306 OLED display uncomment following
U8g2@~2.27.3

View File

@ -0,0 +1,35 @@
# Description
That usermod implements support of simple hand gestures with VL53L0X sensor: on/off and brightness correction.
It can be useful for kitchen strips to avoid any touches.
- on/off - just swipe a hand below your sensor ("shortPressAction" is called and can be customized through WLED macros)
- brightness correction - keep your hand below sensor for 1 second to switch to "brightness" mode.
Configure brightness by changing distance to the sensor (see parameters below for customization).
"macroLongPress" is also called here.
## Installation
1. Attach VL53L0X sensor to i2c pins according to default pins for your board.
2. Add `-D USERMOD_VL53L0X_GESTURES` to your build flags at platformio.ini (plaformio_override.ini) for needed environment.
In my case, for example: `build_flags = ${common.build_flags_esp8266} -D RLYPIN=12 -D USERMOD_VL53L0X_GESTURES`
3. Add "pololu/VL53L0X" dependency below to `lib_deps` like this:
```ini
lib_deps = ${env.lib_deps}
pololu/VL53L0X @ ^1.3.0
```
My entire `platformio_override.ini` for example (for nodemcu board):
```ini
[platformio]
default_envs = nodemcu
[env:nodemcu]
board = nodemcu
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D RLYPIN=12 -D USERMOD_VL53L0X_GESTURES
lib_deps = ${env.lib_deps}
pololu/VL53L0X @ ^1.3.0
```

View File

@ -0,0 +1,121 @@
/*
* That usermod implements support of simple hand gestures with VL53L0X sensor: on/off and brightness correction.
* It can be useful for kitchen strips to avoid any touches.
* - on/off - just swipe a hand below your sensor ("shortPressAction" is called and can be customized through WLED macros)
* - brightness correction - keep your hand below sensor for 1 second to switch to "brightness" mode.
* Configure brightness by changing distance to the sensor (see parameters below for customization).
* "macroLongPress" is also called here.
*
* Enabling this mod usermod:
* 1. Attach VL53L0X sensor to i2c pins according to default pins for your board.
* 2. Add "-D USERMOD_VL53L0X_GESTURES" to your build flags at platformio.ini (plaformio_override.ini) for needed environment.
* In my case, for example: build_flags = ${common.build_flags_esp8266} -D RLYPIN=12 -D USERMOD_VL53L0X_GESTURES
* 3. Add "pololu/VL53L0X" dependency to lib_deps like this:
* lib_deps = ${env.lib_deps}
* pololu/VL53L0X @ ^1.3.0
*/
#pragma once
#include "wled.h"
#include <Wire.h>
#include <VL53L0X.h>
#ifndef VL53L0X_MAX_RANGE_MM
#define VL53L0X_MAX_RANGE_MM 230 // max height in millimiters to react for motions
#endif
#ifndef VL53L0X_MIN_RANGE_OFFSET
#define VL53L0X_MIN_RANGE_OFFSET 60 // minimal range in millimiters that sensor can detect. Used in long motions to correct brightnes calculation.
#endif
#ifndef VL53L0X_DELAY_MS
#define VL53L0X_DELAY_MS 100 // how often to get data from sensor
#endif
#ifndef VL53L0X_LONG_MOTION_DELAY_MS
#define VL53L0X_LONG_MOTION_DELAY_MS 1000 // how often to get data from sensor
#endif
class UsermodVL53L0XGestures : public Usermod {
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long lastTime = 0;
VL53L0X sensor;
bool wasMotionBefore = false;
bool isLongMotion = false;
unsigned long motionStartTime = 0;
public:
void setup() {
Wire.begin();
sensor.setTimeout(150);
if (!sensor.init())
{
DEBUG_PRINTLN(F("Failed to detect and initialize VL53L0X sensor!"));
} else {
sensor.setMeasurementTimingBudget(20000); // set high speed mode
}
}
void loop() {
if (millis() - lastTime > VL53L0X_DELAY_MS)
{
lastTime = millis();
int range = sensor.readRangeSingleMillimeters();
DEBUG_PRINTF(F("range: %d, brightness: %d"), range, bri);
if (range < VL53L0X_MAX_RANGE_MM)
{
if (!wasMotionBefore)
{
motionStartTime = millis();
DEBUG_PRINTF(F("motionStartTime: %d"), motionStartTime);
}
wasMotionBefore = true;
if (millis() - motionStartTime > VL53L0X_LONG_MOTION_DELAY_MS) //long motion
{
DEBUG_PRINTF(F("long motion: %d"), motionStartTime);
if (!isLongMotion)
{
if (macroLongPress)
{
applyMacro(macroLongPress);
}
isLongMotion = true;
}
// set brightness according to range
bri = (VL53L0X_MAX_RANGE_MM - max(range, VL53L0X_MIN_RANGE_OFFSET)) * 255 / (VL53L0X_MAX_RANGE_MM - VL53L0X_MIN_RANGE_OFFSET);
DEBUG_PRINTF(F("new brightness: %d"), bri);
colorUpdated(1);
}
} else if (wasMotionBefore) { //released
long dur = millis() - motionStartTime;
if (!isLongMotion)
{ //short press
DEBUG_PRINTF(F("shortPressAction..."));
shortPressAction();
}
wasMotionBefore = false;
isLongMotion = false;
}
}
}
/*
* 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_VL53L0X;
}
};

View File

@ -4,7 +4,7 @@ default_envs = d1_mini
[env:esp32dev]
board = esp32dev
platform = espressif32@3.1.1
platform = espressif32@3.2
build_unflags = ${common.build_unflags}
build_flags =
${common.build_flags_esp32}

View File

@ -418,28 +418,45 @@ uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
/*
* Running lights effect with smooth sine transition base.
*/
uint16_t WS2812FX::running_base(bool saw) {
uint16_t WS2812FX::running_base(bool saw, bool dual=false) {
uint8_t x_scale = SEGMENT.intensity >> 2;
uint32_t counter = (now * SEGMENT.speed) >> 9;
for(uint16_t i = 0; i < SEGLEN; i++) {
uint8_t s = 0;
uint8_t a = i*x_scale - counter;
uint16_t a = i*x_scale - counter;
if (saw) {
a &= 0xFF;
if (a < 16)
{
a = 192 + a*8;
} else {
a = map(a,16,255,64,192);
}
a = 255 - a;
}
s = sin8(a);
setPixelColor(i, color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), s));
uint8_t s = dual ? sin_gap(a) : sin8(a);
uint32_t ca = color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s);
if (dual) {
uint16_t b = (SEGLEN-1-i)*x_scale - counter;
uint8_t t = sin_gap(b);
uint32_t cb = color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), t);
ca = color_blend(ca, cb, 127);
}
setPixelColor(i, ca);
}
return FRAMETIME;
}
/*
* Running lights in opposite directions.
* Idea: Make the gap width controllable with a third slider in the future
*/
uint16_t WS2812FX::mode_running_dual(void) {
return running_base(false, true);
}
/*
* Running lights effect with smooth sine transition.
*/
@ -1306,14 +1323,6 @@ uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) {
}
/*
* Alternating white/red/black pixels running. PLACEHOLDER
*/
uint16_t WS2812FX::mode_circus_combustus(void) {
return tricolor_chase(RED, WHITE);
}
/*
* Tricolor chase mode
*/
@ -3074,8 +3083,9 @@ uint16_t WS2812FX::mode_drip(void)
if (drops[j].pos < 0) drops[j].pos = 0;
drops[j].vel += gravity; // gravity is negative
for (uint8_t i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
setPixelColor(constrain(uint16_t(drops[j].pos)+i,0,SEGLEN-1),color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling
for (uint16_t i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
setPixelColor(pos,color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling
}
if (drops[j].colIndex > 2) { // during bounce, some water is on the floor

View File

@ -166,7 +166,7 @@
#define FX_MODE_POLICE_ALL 49
#define FX_MODE_TWO_DOTS 50
#define FX_MODE_TWO_AREAS 51
#define FX_MODE_CIRCUS_COMBUSTUS 52
#define FX_MODE_RUNNING_DUAL 52
#define FX_MODE_HALLOWEEN 53
#define FX_MODE_TRICOLOR_CHASE 54
#define FX_MODE_TRICOLOR_WIPE 55
@ -504,7 +504,7 @@ class WS2812FX {
_mode[FX_MODE_POLICE_ALL] = &WS2812FX::mode_police_all;
_mode[FX_MODE_TWO_DOTS] = &WS2812FX::mode_two_dots;
_mode[FX_MODE_TWO_AREAS] = &WS2812FX::mode_two_areas;
_mode[FX_MODE_CIRCUS_COMBUSTUS] = &WS2812FX::mode_circus_combustus;
_mode[FX_MODE_RUNNING_DUAL] = &WS2812FX::mode_running_dual;
_mode[FX_MODE_HALLOWEEN] = &WS2812FX::mode_halloween;
_mode[FX_MODE_TRICOLOR_CHASE] = &WS2812FX::mode_tricolor_chase;
_mode[FX_MODE_TRICOLOR_WIPE] = &WS2812FX::mode_tricolor_wipe;
@ -633,6 +633,7 @@ class WS2812FX {
getMainSegmentId(void),
gamma8(uint8_t),
gamma8_cal(uint8_t, float),
sin_gap(uint16_t),
get_random_wheel_index(uint8_t);
int8_t
@ -720,7 +721,7 @@ class WS2812FX {
mode_police_all(void),
mode_two_dots(void),
mode_two_areas(void),
mode_circus_combustus(void),
mode_running_dual(void),
mode_bicolor_chase(void),
mode_tricolor_chase(void),
mode_tricolor_wipe(void),
@ -818,7 +819,7 @@ class WS2812FX {
color_wipe(bool, bool),
dynamic(bool),
scan(bool),
running_base(bool),
running_base(bool,bool),
larson_scanner(bool),
sinelon_base(bool,bool),
dissolve(uint32_t),
@ -872,7 +873,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"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","Aurora","Stream",
"Scanner","Lighthouse","Fireworks","Rain","Tetrix","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","Running Dual","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",
"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",

View File

@ -207,7 +207,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) { // watch for group out of bounds condition
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
if (IS_MIRROR) { //set the corresponding mirrored pixel
uint16_t indexMir = SEGMENT.stop + SEGMENT.start - indexSet - 1;
if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir];
@ -765,6 +765,12 @@ uint16_t WS2812FX::triwave16(uint16_t in)
return 0xFFFF - (in - 0x8000)*2;
}
uint8_t WS2812FX::sin_gap(uint16_t in) {
if (in & 0x100) return 0;
//if (in > 255) return 0;
return sin8(in + 192); //correct phase shift of sine so that it starts and stops at 0
}
/*
* Generates a tristate square wave w/ attac & decay
* @param x input value 0-255

View File

@ -4,6 +4,8 @@
* Physical IO
*/
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
void shortPressAction()
{
if (!macroButton)
@ -25,10 +27,42 @@ bool isButtonPressed()
}
void handleSwitch()
{
if (buttonPressedBefore != isButtonPressed()) {
buttonPressedTime = millis();
buttonPressedBefore = !buttonPressedBefore;
}
if (buttonLongPressed == buttonPressedBefore) return;
if (millis() - buttonPressedTime > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
if (buttonPressedBefore) { //LOW, falling edge, switch closed
if (macroButton) applyPreset(macroButton);
else { //turn on
if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
}
} else { //HIGH, rising edge, switch opened
if (macroLongPress) applyPreset(macroLongPress);
else { //turn off
if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
}
}
buttonLongPressed = buttonPressedBefore; //save the last "long term" switch state
}
}
void handleButton()
{
if (btnPin<0 || !buttonEnabled) return;
if (btnPin<0 || buttonType < BTN_TYPE_PUSH) return;
if (buttonType == BTN_TYPE_SWITCH) { //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NO gpio0)
handleSwitch(); return;
}
//momentary button logic
if (isButtonPressed()) //pressed
{
if (!buttonPressedBefore) buttonPressedTime = millis();
@ -48,7 +82,7 @@ void handleButton()
else if (!isButtonPressed() && buttonPressedBefore) //released
{
long dur = millis() - buttonPressedTime;
if (dur < 50) {buttonPressedBefore = false; return;} //too short "press", debounce
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore = false; return;} //too short "press", debounce
bool doublePress = buttonWaitTime;
buttonWaitTime = 0;

View File

@ -141,9 +141,9 @@ void deserializeConfig() {
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
CJSON(buttonEnabled, hw_btn_ins_0["type"]);
CJSON(buttonType, hw_btn_ins_0["type"]);
int hw_btn_pin = hw_btn_ins_0["pin"][0];
if (hw_btn_pin>=0 && pinManager.allocatePin(hw_btn_pin,false)) {
if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
} else {
@ -159,7 +159,7 @@ void deserializeConfig() {
#ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = hw["ir"]["pin"] | -1; // 4
if (hw_ir_pin >=0 && pinManager.allocatePin(hw_ir_pin,false)) {
if (pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
@ -484,7 +484,7 @@ void serializeConfig() {
// button BTNPIN
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0["type"] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
hw_btn_ins_0["type"] = buttonType;
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(btnPin);

View File

@ -34,6 +34,7 @@
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
#define USERMOD_ID_MODE_SORT 11 //Usermod "usermod_v2_mode_sort.h"
#define USERMOD_ID_VL53L0X 12 //Usermod "usermod_vl53l0x_gestures.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
@ -136,7 +137,7 @@
#define BTN_TYPE_RESERVED 1
#define BTN_TYPE_PUSH 2
#define BTN_TYPE_PUSH_ACT_HIGH 3 //not implemented
#define BTN_TYPE_SWITCH 4 //not implemented
#define BTN_TYPE_SWITCH 4
#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented
//Ethernet board types

View File

@ -150,12 +150,12 @@ function loadBg(iUrl)
if (iUrl == "") {
var today = new Date();
var hol = [
[0,11,24,5,"https://aircoookie.github.io/xmas.png"], // christmas
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
[0,2,17,1,"https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day
[2022,3,16,3,"https://aircoookie.github.io/easter.png"],
[2023,3,8,3,"https://aircoookie.github.io/easter.png"],
[2024,2,30,3,"https://aircoookie.github.io/easter.png"]
]
[2022,3,17,2,"https://aircoookie.github.io/easter.png"],
[2023,3,9,2,"https://aircoookie.github.io/easter.png"],
[2024,2,31,2,"https://aircoookie.github.io/easter.png"]
];
for (var i=0; i<hol.length; i++) {
var yr = hol[i][0]==0 ? today.getFullYear() : hol[i][0];
var hs = new Date(yr,hol[i][1],hol[i][2]);

View File

@ -18,7 +18,12 @@ function GetV(){var d=document;}
</div>
<h2>Sync setup</h2>
<h3>Button setup</h3>
On/Off button enabled: <input type="checkbox" name="BT"><br>
Button type:
<select name=BT>
<option value=0>Disabled</option>
<option value=2>Pushbutton</option>
<option value=4>Switch</option>
</select><br>
Infrared remote:
<select name=IR>
<option value=0>Disabled</option>

View File

@ -27,7 +27,7 @@
ldS();
}
function check(o,k) {
var n = o.name.substr(-6);
var n = o.name.replace("[]","").substr(-4);
if (o.type=="number" && n.substr(0,4)=="_pin") {
for (var i=0; i<pins.length; i++) {
if (k==pinO[i]) continue;

View File

@ -221,8 +221,9 @@ var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki
id="form_s" name="Sf" method="post"><div class="toprow"><div class="helpB">
<button type="button" onclick="H()">?</button></div><button type="button"
onclick="B()">Back</button><button type="submit">Save</button><hr></div><h2>
Sync setup</h2><h3>Button setup</h3>On/Off button enabled: <input
type="checkbox" name="BT"><br>Infrared remote: <select name="IR"><option
Sync setup</h2><h3>Button setup</h3>Button type: <select name="BT"><option
value="0">Disabled</option><option value="2">Pushbutton</option><option
value="4">Switch</option></select><br>Infrared remote: <select name="IR"><option
value="0">Disabled</option><option value="1">24-key RGB</option><option
value="2">24-key with CT</option><option value="3">40-key blue</option><option
value="4">44-key RGB</option><option value="5">21-key RGB</option><option

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include "src/dependencies/timezone/Timezone.h"
#include "wled.h"
#include "wled_math.h"
/*
* Acquires time from NTP server
@ -316,8 +317,8 @@ void checkTimers()
// get sunrise (or sunset) time (in minutes) for a given day at a given geo location
int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunset=false) {
//1. first calculate the day of the year
float N1 = floor(275 * month / 9);
float N2 = floor((month + 9) / 12);
float N1 = 275 * month / 9;
float N2 = (month + 9) / 12;
float N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3));
float N = N1 - (N2 * N3) + day - 30;
@ -329,10 +330,10 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse
float M = (0.9856 * t) - 3.289;
//4. calculate the Sun's true longitude
float L = fmod(M + (1.916 * sin(DEG_TO_RAD*M)) + (0.020 * sin(2*DEG_TO_RAD*M)) + 282.634, 360.0);
float L = fmod(M + (1.916 * sin_t(DEG_TO_RAD*M)) + (0.020 * sin_t(2*DEG_TO_RAD*M)) + 282.634, 360.0);
//5a. calculate the Sun's right ascension
float RA = fmod(RAD_TO_DEG*atan(0.91764 * tan(DEG_TO_RAD*L)), 360.0);
float RA = fmod(RAD_TO_DEG*atan_t(0.91764 * tan_t(DEG_TO_RAD*L)), 360.0);
//5b. right ascension value needs to be in the same quadrant as L
float Lquadrant = floor( L/90) * 90;
@ -343,16 +344,16 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse
RA /= 15.;
//6. calculate the Sun's declination
float sinDec = 0.39782 * sin(DEG_TO_RAD*L);
float cosDec = cos(asin(sinDec));
float sinDec = 0.39782 * sin_t(DEG_TO_RAD*L);
float cosDec = cos_t(asin_t(sinDec));
//7a. calculate the Sun's local hour angle
float cosH = (sin(DEG_TO_RAD*ZENITH) - (sinDec * sin(DEG_TO_RAD*lat))) / (cosDec * cos(DEG_TO_RAD*lat));
float cosH = (sin_t(DEG_TO_RAD*ZENITH) - (sinDec * sin_t(DEG_TO_RAD*lat))) / (cosDec * cos_t(DEG_TO_RAD*lat));
if (cosH > 1 && !sunset) return 0; // the sun never rises on this location (on the specified date)
if (cosH < -1 && sunset) return 0; // the sun never sets on this location (on the specified date)
//7b. finish calculating H and convert into hours
float H = sunset ? RAD_TO_DEG*acos(cosH) : 360 - RAD_TO_DEG*acos(cosH);
float H = sunset ? RAD_TO_DEG*acos_t(cosH) : 360 - RAD_TO_DEG*acos_t(cosH);
H /= 15.;
//8. calculate local mean time of rising/setting

View File

@ -197,7 +197,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//SYNC
if (subPage == 4)
{
buttonEnabled = request->hasArg(F("BT"));
buttonType = request->arg(F("BT")).toInt();
irEnabled = request->arg(F("IR")).toInt();
int t = request->arg(F("UP")).toInt();
if (t > 0) udpPort = t;

View File

@ -45,6 +45,11 @@
#include "../usermods/DHT/usermod_dht.h"
#endif
#ifdef USERMOD_VL53L0X_GESTURES
#include <Wire.h> //it's needed here to correctly resolve dependencies
#include "../usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h"
#endif
void registerUsermods()
{
/*
@ -87,4 +92,8 @@ void registerUsermods()
#ifdef USERMOD_DHT
usermods.add(new UsermodDHT());
#endif
#ifdef USERMOD_VL53L0X_GESTURES
usermods.add(new UsermodVL53L0XGestures());
#endif
}

View File

@ -239,7 +239,7 @@ void WLED::loop()
lastMqttReconnectAttempt = 0;
}
if (millis() - lastMqttReconnectAttempt > 30000) {
lastMqttReconnectAttempt = millis(); // don't do it in initMqtt() since MQTT may be disabled
lastMqttReconnectAttempt = millis();
initMqtt();
yield();
// refresh WLED nodes list
@ -441,7 +441,8 @@ void WLED::beginStrip()
if (rlyPin>=0) digitalWrite(rlyPin, (bri ? rlyMde : !rlyMde));
// disable button if it is "pressed" unintentionally
if (btnPin>=0 && isButtonPressed()) buttonEnabled = false;
if (btnPin>=0 && buttonType == BTN_TYPE_PUSH && isButtonPressed())
buttonType = BTN_TYPE_NONE;
}
void WLED::initAP(bool resetAP)

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2104121
#define VERSION 2104141
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG
@ -182,12 +182,12 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
// Hardware CONFIG (only changeble HERE, not at runtime)
// LED strip pin, button pin and IR pin changeable in NpbWrapper.h!
#ifndef BTNPIN
WLED_GLOBAL int8_t btnPin _INIT(-1);
WLED_GLOBAL int8_t btnPin _INIT(0);
#else
WLED_GLOBAL int8_t btnPin _INIT(BTNPIN);
#endif
#ifndef RLYPIN
WLED_GLOBAL int8_t rlyPin _INIT(-1);
WLED_GLOBAL int8_t rlyPin _INIT(12);
#else
WLED_GLOBAL int8_t rlyPin _INIT(RLYPIN);
#endif
@ -198,7 +198,7 @@ WLED_GLOBAL bool rlyMde _INIT(true);
WLED_GLOBAL bool rlyMde _INIT(RLYMDE);
#endif
#ifndef IRPIN
WLED_GLOBAL int8_t irPin _INIT(-1);
WLED_GLOBAL int8_t irPin _INIT(4);
#else
WLED_GLOBAL int8_t irPin _INIT(IRPIN);
#endif
@ -253,7 +253,7 @@ WLED_GLOBAL NodesMap Nodes;
WLED_GLOBAL bool nodeListEnabled _INIT(true);
WLED_GLOBAL bool nodeBroadcastEnabled _INIT(true);
WLED_GLOBAL bool buttonEnabled _INIT(true);
WLED_GLOBAL byte buttonType _INIT(BTN_TYPE_PUSH);
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port

View File

@ -93,7 +93,7 @@ void loadSettingsFromEEPROM()
notifyButton = EEPROM.read(230);
notifyTwice = EEPROM.read(231);
buttonEnabled = EEPROM.read(232);
buttonType = EEPROM.read(232) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
staticIP[0] = EEPROM.read(234);
staticIP[1] = EEPROM.read(235);

71
wled00/wled_math.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef WLED_MATH_H
#define WLED_MATH_H
/*
* Contains some trigonometric functions.
* The ANSI C equivalents are likely faster, but using any sin/cos/tan function incurs a memory penalty of 460 bytes on ESP8266, likely for lookup tables.
* This implementation has no extra static memory usage.
*
* Source of the cos_t() function: https://web.eecs.utk.edu/~azh/blog/cosine.html (cos_taylor_literal_6terms)
*/
#include <Arduino.h> //PI constant
#define modd(x, y) ((x) - (int)((x) / (y)) * (y))
double cos_t(double x)
{
x = modd(x, TWO_PI);
char sign = 1;
if (x > PI)
{
x -= PI;
sign = -1;
}
double xx = x * x;
return sign * (1 - ((xx) / (2)) + ((xx * xx) / (24)) - ((xx * xx * xx) / (720)) + ((xx * xx * xx * xx) / (40320)) - ((xx * xx * xx * xx * xx) / (3628800)) + ((xx * xx * xx * xx * xx * xx) / (479001600)));
}
double sin_t(double x) {
return cos_t(HALF_PI - x);
}
double tan_t(double x) {
double c = cos_t(x);
if (c==0.0) return 0;
return sin_t(x) / c;
}
//https://stackoverflow.com/questions/3380628
// Absolute error <= 6.7e-5
float acos_t(float x) {
float negate = float(x < 0);
x = std::abs(x);
float ret = -0.0187293;
ret = ret * x;
ret = ret + 0.0742610;
ret = ret * x;
ret = ret - 0.2121144;
ret = ret * x;
ret = ret + HALF_PI;
ret = ret * sqrt(1.0-x);
ret = ret - 2 * negate * ret;
return negate * PI + ret;
}
float asin_t(float x) {
return HALF_PI - acos_t(x);
}
//https://stackoverflow.com/a/42542593
#define A 0.0776509570923569
#define B -0.287434475393028
#define C ((HALF_PI/2) - A - B)
double atan_t(double x) {
double xx = x * x;
return ((A*xx + B)*xx + C)*x;
}
#endif

View File

@ -394,7 +394,7 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == 4)
{
sappend('c',SET_F("BT"),buttonEnabled);
sappend('v',SET_F("BT"),buttonType);
sappend('v',SET_F("IR"),irEnabled);
sappend('v',SET_F("UP"),udpPort);
sappend('v',SET_F("U2"),udpPort2);