2020-03-25 08:00:55 +00:00
# include "wled.h"
2020-03-25 09:14:23 +00:00
2016-12-30 23:38:51 +00:00
/*
* Physical IO
*/
2022-03-15 08:55:23 +00:00
# define WLED_DEBOUNCE_THRESHOLD 50 // only consider button input of at least 50ms as valid (debouncing)
# define WLED_LONG_PRESS 600 // long press if button is released after held for at least 600ms
# define WLED_DOUBLE_PRESS 350 // double press if another press within 350ms after a short press
2024-04-26 14:39:32 +00:00
# define WLED_LONG_REPEATED_ACTION 400 // how often a repeated action (e.g. dimming) is fired on long press on button IDs >0
2022-03-15 08:55:23 +00:00
# define WLED_LONG_AP 5000 // how long button 0 needs to be held to activate WLED-AP
# define WLED_LONG_FACTORY_RESET 10000 // how long button 0 needs to be held to trigger a factory reset
2024-04-27 10:25:34 +00:00
# define WLED_LONG_BRI_STEPS 16 // how much to increase/decrease the brightness with each long press repetition
2021-04-11 22:45:33 +00:00
2021-06-03 10:18:11 +00:00
static const char _mqtt_topic_button [ ] PROGMEM = " %s/button/%d " ; // optimize flash usage
2024-04-26 16:23:34 +00:00
static bool buttonBriDirection = false ; // true: increase brightness, false: decrease brightness
2021-06-03 10:18:11 +00:00
2021-05-20 17:54:07 +00:00
void shortPressAction ( uint8_t b )
2019-03-13 10:13:03 +00:00
{
2021-10-31 10:57:03 +00:00
if ( ! macroButton [ b ] ) {
switch ( b ) {
2022-02-20 21:24:11 +00:00
case 0 : toggleOnOff ( ) ; stateUpdated ( CALL_MODE_BUTTON ) ; break ;
2022-02-22 09:42:00 +00:00
case 1 : + + effectCurrent % = strip . getModeCount ( ) ; stateChanged = true ; colorUpdated ( CALL_MODE_BUTTON ) ; break ;
2021-10-31 10:57:03 +00:00
}
2019-03-13 10:13:03 +00:00
} else {
2021-12-11 22:44:21 +00:00
applyPreset ( macroButton [ b ] , CALL_MODE_BUTTON_PRESET ) ;
2019-03-13 10:13:03 +00:00
}
2021-06-03 10:18:11 +00:00
2023-01-12 19:35:34 +00:00
# ifndef WLED_DISABLE_MQTT
2021-06-03 10:18:11 +00:00
// publish MQTT message
2021-07-01 18:51:52 +00:00
if ( buttonPublishMqtt & & WLED_MQTT_CONNECTED ) {
2021-06-03 10:18:11 +00:00
char subuf [ 64 ] ;
sprintf_P ( subuf , _mqtt_topic_button , mqttDeviceTopic , ( int ) b ) ;
mqtt - > publish ( subuf , 0 , false , " short " ) ;
}
2023-01-12 19:35:34 +00:00
# endif
2019-03-13 10:13:03 +00:00
}
2021-10-31 10:57:03 +00:00
void longPressAction ( uint8_t b )
{
if ( ! macroLongPress [ b ] ) {
switch ( b ) {
2022-02-20 21:24:11 +00:00
case 0 : setRandomColor ( col ) ; colorUpdated ( CALL_MODE_BUTTON ) ; break ;
2024-04-26 14:39:32 +00:00
case 1 :
if ( buttonBriDirection ) {
if ( bri = = 255 ) break ; // avoid unnecessary updates to brightness
if ( bri > = 255 - WLED_LONG_BRI_STEPS ) bri = 255 ;
else bri + = WLED_LONG_BRI_STEPS ;
} else {
if ( bri = = 1 ) break ; // avoid unnecessary updates to brightness
if ( bri < = WLED_LONG_BRI_STEPS ) bri = 1 ;
else bri - = WLED_LONG_BRI_STEPS ;
}
stateUpdated ( CALL_MODE_BUTTON ) ;
buttonPressedTime [ b ] = millis ( ) ;
break ; // repeatable action
2021-10-31 10:57:03 +00:00
}
} else {
2021-12-11 22:44:21 +00:00
applyPreset ( macroLongPress [ b ] , CALL_MODE_BUTTON_PRESET ) ;
2021-10-31 10:57:03 +00:00
}
2023-01-12 19:35:34 +00:00
# ifndef WLED_DISABLE_MQTT
2021-10-31 10:57:03 +00:00
// publish MQTT message
if ( buttonPublishMqtt & & WLED_MQTT_CONNECTED ) {
char subuf [ 64 ] ;
sprintf_P ( subuf , _mqtt_topic_button , mqttDeviceTopic , ( int ) b ) ;
mqtt - > publish ( subuf , 0 , false , " long " ) ;
}
2023-01-12 19:35:34 +00:00
# endif
2021-10-31 10:57:03 +00:00
}
void doublePressAction ( uint8_t b )
{
if ( ! macroDoublePress [ b ] ) {
switch ( b ) {
//case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; //instant short press on button 0 if no macro set
2022-02-20 21:24:11 +00:00
case 1 : + + effectPalette % = strip . getPaletteCount ( ) ; colorUpdated ( CALL_MODE_BUTTON ) ; break ;
2021-10-31 10:57:03 +00:00
}
} else {
2021-12-11 22:44:21 +00:00
applyPreset ( macroDoublePress [ b ] , CALL_MODE_BUTTON_PRESET ) ;
2021-10-31 10:57:03 +00:00
}
2023-01-12 19:35:34 +00:00
# ifndef WLED_DISABLE_MQTT
2021-10-31 10:57:03 +00:00
// publish MQTT message
if ( buttonPublishMqtt & & WLED_MQTT_CONNECTED ) {
char subuf [ 64 ] ;
sprintf_P ( subuf , _mqtt_topic_button , mqttDeviceTopic , ( int ) b ) ;
mqtt - > publish ( subuf , 0 , false , " double " ) ;
}
2023-01-12 19:35:34 +00:00
# endif
2021-10-31 10:57:03 +00:00
}
2021-05-20 17:54:07 +00:00
bool isButtonPressed ( uint8_t i )
2020-09-20 14:12:46 +00:00
{
2021-05-20 17:54:07 +00:00
if ( btnPin [ i ] < 0 ) return false ;
2024-07-09 19:50:27 +00:00
unsigned pin = btnPin [ i ] ;
2022-02-09 18:59:17 +00:00
2021-05-20 17:54:07 +00:00
switch ( buttonType [ i ] ) {
case BTN_TYPE_NONE :
case BTN_TYPE_RESERVED :
break ;
case BTN_TYPE_PUSH :
case BTN_TYPE_SWITCH :
2022-02-09 18:59:17 +00:00
if ( digitalRead ( pin ) = = LOW ) return true ;
2021-05-20 17:54:07 +00:00
break ;
case BTN_TYPE_PUSH_ACT_HIGH :
2021-06-03 10:18:11 +00:00
case BTN_TYPE_PIR_SENSOR :
2022-02-09 18:59:17 +00:00
if ( digitalRead ( pin ) = = HIGH ) return true ;
2021-05-20 17:54:07 +00:00
break ;
case BTN_TYPE_TOUCH :
2023-11-22 14:35:11 +00:00
case BTN_TYPE_TOUCH_SWITCH :
2022-01-24 10:34:02 +00:00
# if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
2024-02-18 14:52:36 +00:00
# ifdef SOC_TOUCH_VERSION_2 //ESP32 S2 and S3 provide a function to check touch state (state is updated in interrupt)
2024-04-07 20:12:01 +00:00
if ( touchInterruptGetLastStatus ( pin ) ) return true ;
2024-02-18 14:52:36 +00:00
# else
2024-04-07 20:12:01 +00:00
if ( digitalPinToTouchChannel ( btnPin [ i ] ) > = 0 & & touchRead ( pin ) < = touchThreshold ) return true ;
2024-02-18 14:52:36 +00:00
# endif
2021-05-20 17:54:07 +00:00
# endif
2024-02-18 14:52:36 +00:00
break ;
2021-05-20 17:54:07 +00:00
}
2020-09-20 14:12:46 +00:00
return false ;
}
2021-05-20 17:54:07 +00:00
void handleSwitch ( uint8_t b )
2021-04-11 22:45:33 +00:00
{
2021-06-03 10:18:11 +00:00
// isButtonPressed() handles inverted/noninverted logic
2021-05-20 17:54:07 +00:00
if ( buttonPressedBefore [ b ] ! = isButtonPressed ( b ) ) {
2024-09-10 13:20:34 +00:00
DEBUG_PRINTF_P ( PSTR ( " Switch: State changed %u \n " ) , b ) ;
2021-05-20 17:54:07 +00:00
buttonPressedTime [ b ] = millis ( ) ;
buttonPressedBefore [ b ] = ! buttonPressedBefore [ b ] ;
2021-04-11 22:45:33 +00:00
}
2021-05-20 17:54:07 +00:00
if ( buttonLongPressed [ b ] = = buttonPressedBefore [ b ] ) return ;
2023-01-06 08:24:29 +00:00
2021-05-20 17:54:07 +00:00
if ( millis ( ) - buttonPressedTime [ b ] > WLED_DEBOUNCE_THRESHOLD ) { //fire edge event only after 50ms without change (debounce)
2024-09-10 13:20:34 +00:00
DEBUG_PRINTF_P ( PSTR ( " Switch: Activating %u \n " ) , b ) ;
2021-06-03 10:18:11 +00:00
if ( ! buttonPressedBefore [ b ] ) { // on -> off
2024-09-10 13:20:34 +00:00
DEBUG_PRINTF_P ( PSTR ( " Switch: On -> Off (%u) \n " ) , b ) ;
2021-12-11 22:44:21 +00:00
if ( macroButton [ b ] ) applyPreset ( macroButton [ b ] , CALL_MODE_BUTTON_PRESET ) ;
2021-04-11 22:45:33 +00:00
else { //turn on
2022-02-20 21:24:11 +00:00
if ( ! bri ) { toggleOnOff ( ) ; stateUpdated ( CALL_MODE_BUTTON ) ; }
2023-01-06 08:24:29 +00:00
}
2021-06-03 10:18:11 +00:00
} else { // off -> on
2024-09-10 13:20:34 +00:00
DEBUG_PRINTF_P ( PSTR ( " Switch: Off -> On (%u) \n " ) , b ) ;
2021-12-11 22:44:21 +00:00
if ( macroLongPress [ b ] ) applyPreset ( macroLongPress [ b ] , CALL_MODE_BUTTON_PRESET ) ;
2021-04-11 22:45:33 +00:00
else { //turn off
2022-02-20 21:24:11 +00:00
if ( bri ) { toggleOnOff ( ) ; stateUpdated ( CALL_MODE_BUTTON ) ; }
2023-01-06 08:24:29 +00:00
}
2021-04-11 22:45:33 +00:00
}
2021-06-03 10:18:11 +00:00
2023-01-12 19:35:34 +00:00
# ifndef WLED_DISABLE_MQTT
2021-06-03 10:18:11 +00:00
// publish MQTT message
2021-07-01 18:51:52 +00:00
if ( buttonPublishMqtt & & WLED_MQTT_CONNECTED ) {
2021-06-03 10:18:11 +00:00
char subuf [ 64 ] ;
if ( buttonType [ b ] = = BTN_TYPE_PIR_SENSOR ) sprintf_P ( subuf , PSTR ( " %s/motion/%d " ) , mqttDeviceTopic , ( int ) b ) ;
else sprintf_P ( subuf , _mqtt_topic_button , mqttDeviceTopic , ( int ) b ) ;
mqtt - > publish ( subuf , 0 , false , ! buttonPressedBefore [ b ] ? " off " : " on " ) ;
}
2023-01-12 19:35:34 +00:00
# endif
2021-06-03 10:18:11 +00:00
2021-05-20 17:54:07 +00:00
buttonLongPressed [ b ] = buttonPressedBefore [ b ] ; //save the last "long term" switch state
2021-04-11 22:45:33 +00:00
}
}
2022-06-20 14:04:43 +00:00
# define ANALOG_BTN_READ_CYCLE 250 // min time between two analog reading cycles
2023-01-06 08:24:29 +00:00
# define STRIP_WAIT_TIME 6 // max wait time in case of strip.isUpdating()
2022-06-20 20:00:23 +00:00
# define POT_SMOOTHING 0.25f // smoothing factor for raw potentiometer readings
2022-06-20 14:04:43 +00:00
# define POT_SENSITIVITY 4 // changes below this amount are noise (POT scratching, or ADC noise)
2021-05-21 11:33:22 +00:00
void handleAnalog ( uint8_t b )
{
2022-06-22 07:58:21 +00:00
static uint8_t oldRead [ WLED_MAX_BUTTONS ] = { 0 } ;
2022-06-20 19:56:16 +00:00
static float filteredReading [ WLED_MAX_BUTTONS ] = { 0.0f } ;
2024-07-09 19:50:27 +00:00
unsigned rawReading ; // raw value from analogRead, scaled to 12bit
2022-06-20 14:04:43 +00:00
2024-09-10 13:20:34 +00:00
DEBUG_PRINTF_P ( PSTR ( " Analog: Reading button %u \n " ) , b ) ;
2023-12-14 17:32:54 +00:00
2021-05-21 11:33:22 +00:00
# ifdef ESP8266
2022-06-20 14:04:43 +00:00
rawReading = analogRead ( A0 ) < < 2 ; // convert 10bit read to 12bit
2021-05-21 11:33:22 +00:00
# else
2024-07-07 12:18:51 +00:00
if ( ( btnPin [ b ] < 0 ) /*|| (digitalPinToAnalogChannel(btnPin[b]) < 0)*/ ) return ; // pin must support analog ADC - newer esp32 frameworks throw lots of warnings otherwise
2022-06-20 14:04:43 +00:00
rawReading = analogRead ( btnPin [ b ] ) ; // collect at full 12bit resolution
2021-05-21 11:33:22 +00:00
# endif
2022-06-20 14:04:43 +00:00
yield ( ) ; // keep WiFi task running - analog read may take several millis on ESP8266
2022-06-22 07:58:21 +00:00
filteredReading [ b ] + = POT_SMOOTHING * ( ( float ( rawReading ) / 16.0f ) - filteredReading [ b ] ) ; // filter raw input, and scale to [0..255]
2024-07-09 19:50:27 +00:00
unsigned aRead = max ( min ( int ( filteredReading [ b ] ) , 255 ) , 0 ) ; // squash into 8bit
2022-06-20 14:04:43 +00:00
if ( aRead < = POT_SENSITIVITY ) aRead = 0 ; // make sure that 0 and 255 are used
if ( aRead > = 255 - POT_SENSITIVITY ) aRead = 255 ;
2021-06-03 10:18:11 +00:00
if ( buttonType [ b ] = = BTN_TYPE_ANALOG_INVERTED ) aRead = 255 - aRead ;
2021-05-28 12:14:50 +00:00
// remove noise & reduce frequency of UI updates
2022-06-20 14:04:43 +00:00
if ( abs ( int ( aRead ) - int ( oldRead [ b ] ) ) < = POT_SENSITIVITY ) return ; // no significant change in reading
2024-09-10 13:20:34 +00:00
DEBUG_PRINTF_P ( PSTR ( " Analog: Raw = %u \n " ) , rawReading ) ;
DEBUG_PRINTF_P ( PSTR ( " Filtered = %u \n " ) , aRead ) ;
2023-12-14 17:32:54 +00:00
2022-06-22 10:36:47 +00:00
// Unomment the next lines if you still see flickering related to potentiometer
// This waits until strip finishes updating (why: strip was not updating at the start of handleButton() but may have started during analogRead()?)
//unsigned long wait_started = millis();
//while(strip.isUpdating() && (millis() - wait_started < STRIP_WAIT_TIME)) {
// delay(1);
//}
2021-05-21 11:33:22 +00:00
2021-05-25 21:59:43 +00:00
oldRead [ b ] = aRead ;
2021-05-21 11:33:22 +00:00
// if no macro for "short press" and "long press" is defined use brightness control
if ( ! macroButton [ b ] & & ! macroLongPress [ b ] ) {
2024-09-10 13:20:34 +00:00
DEBUG_PRINTF_P ( PSTR ( " Analog: Action = %u \n " ) , macroDoublePress [ b ] ) ;
2021-05-28 06:47:15 +00:00
// if "double press" macro defines which option to change
2021-05-25 21:59:43 +00:00
if ( macroDoublePress [ b ] > = 250 ) {
2021-05-28 06:47:15 +00:00
// global brightness
2021-05-25 21:59:43 +00:00
if ( aRead = = 0 ) {
briLast = bri ;
bri = 0 ;
2023-09-07 16:55:13 +00:00
} else {
2024-10-26 13:16:11 +00:00
if ( bri = = 0 ) strip . restartRuntime ( ) ;
2021-05-28 12:14:50 +00:00
bri = aRead ;
2021-05-28 06:47:15 +00:00
}
} else if ( macroDoublePress [ b ] = = 249 ) {
// effect speed
2021-05-28 12:14:50 +00:00
effectSpeed = aRead ;
2021-05-28 06:47:15 +00:00
} else if ( macroDoublePress [ b ] = = 248 ) {
// effect intensity
2021-05-28 12:14:50 +00:00
effectIntensity = aRead ;
2021-05-28 06:47:15 +00:00
} else if ( macroDoublePress [ b ] = = 247 ) {
// selected palette
2021-05-28 12:14:50 +00:00
effectPalette = map ( aRead , 0 , 252 , 0 , strip . getPaletteCount ( ) - 1 ) ;
2022-06-20 14:04:43 +00:00
effectPalette = constrain ( effectPalette , 0 , strip . getPaletteCount ( ) - 1 ) ; // map is allowed to "overshoot", so we need to contrain the result
2021-05-30 00:03:32 +00:00
} else if ( macroDoublePress [ b ] = = 200 ) {
// primary color, hue, full saturation
colorHStoRGB ( aRead * 256 , 255 , col ) ;
2021-05-21 11:33:22 +00:00
} else {
// otherwise use "double press" for segment selection
2022-07-06 11:13:54 +00:00
Segment & seg = strip . getSegment ( macroDoublePress [ b ] ) ;
2021-05-21 11:33:22 +00:00
if ( aRead = = 0 ) {
2022-08-23 14:00:50 +00:00
seg . setOption ( SEG_OPTION_ON , false ) ; // off (use transition)
2021-05-21 11:33:22 +00:00
} else {
2022-07-10 20:23:25 +00:00
seg . setOpacity ( aRead ) ;
2022-08-23 14:00:50 +00:00
seg . setOption ( SEG_OPTION_ON , true ) ; // on (use transition)
2021-05-21 11:33:22 +00:00
}
2021-05-25 21:59:43 +00:00
// this will notify clients of update (websockets,mqtt,etc)
2021-07-09 16:54:28 +00:00
updateInterfaces ( CALL_MODE_BUTTON ) ;
2021-05-21 11:33:22 +00:00
}
} else {
2023-12-14 17:32:54 +00:00
DEBUG_PRINTLN ( F ( " Analog: No action " ) ) ;
2021-05-21 11:33:22 +00:00
//TODO:
// we can either trigger a preset depending on the level (between short and long entries)
// or use it for RGBW direct control
}
2021-07-09 16:54:28 +00:00
colorUpdated ( CALL_MODE_BUTTON ) ;
2021-05-21 11:33:22 +00:00
}
2016-11-19 18:39:17 +00:00
void handleButton ( )
{
2024-02-10 10:45:33 +00:00
static unsigned long lastAnalogRead = 0UL ;
2022-08-14 11:58:07 +00:00
static unsigned long lastRun = 0UL ;
2022-01-09 14:13:33 +00:00
unsigned long now = millis ( ) ;
2021-05-25 21:59:43 +00:00
2024-02-10 10:45:33 +00:00
if ( strip . isUpdating ( ) & & ( now - lastRun < ANALOG_BTN_READ_CYCLE + 1 ) ) return ; // don't interfere with strip update (unless strip is updating continuously, e.g. very long strips)
2023-06-02 08:51:16 +00:00
lastRun = now ;
2022-06-20 14:04:43 +00:00
2024-07-09 19:50:27 +00:00
for ( unsigned b = 0 ; b < WLED_MAX_BUTTONS ; b + + ) {
2021-05-28 15:45:14 +00:00
# ifdef ESP8266
2021-06-03 10:18:11 +00:00
if ( ( btnPin [ b ] < 0 & & ! ( buttonType [ b ] = = BTN_TYPE_ANALOG | | buttonType [ b ] = = BTN_TYPE_ANALOG_INVERTED ) ) | | buttonType [ b ] = = BTN_TYPE_NONE ) continue ;
2021-05-28 15:45:14 +00:00
# else
2021-05-25 21:59:43 +00:00
if ( btnPin [ b ] < 0 | | buttonType [ b ] = = BTN_TYPE_NONE ) continue ;
2021-05-28 15:45:14 +00:00
# endif
2021-04-11 22:45:33 +00:00
2024-09-19 19:44:11 +00:00
if ( UsermodManager : : handleButton ( b ) ) continue ; // did usermod handle buttons
2021-10-31 10:57:03 +00:00
2023-06-02 08:51:16 +00:00
if ( buttonType [ b ] = = BTN_TYPE_ANALOG | | buttonType [ b ] = = BTN_TYPE_ANALOG_INVERTED ) { // button is not a button but a potentiometer
2024-02-10 10:45:33 +00:00
if ( now - lastAnalogRead > ANALOG_BTN_READ_CYCLE ) {
2023-04-17 14:25:05 +00:00
handleAnalog ( b ) ;
}
continue ;
2021-05-21 11:33:22 +00:00
}
2021-04-11 22:45:33 +00:00
2023-06-02 08:51:16 +00:00
// button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
2023-11-22 14:35:11 +00:00
if ( buttonType [ b ] = = BTN_TYPE_SWITCH | | buttonType [ b ] = = BTN_TYPE_TOUCH_SWITCH | | buttonType [ b ] = = BTN_TYPE_PIR_SENSOR ) {
2023-04-17 14:25:05 +00:00
handleSwitch ( b ) ;
continue ;
2021-05-20 17:54:07 +00:00
}
2019-10-18 10:19:52 +00:00
2023-06-02 08:51:16 +00:00
// momentary button logic
if ( isButtonPressed ( b ) ) { // pressed
// if all macros are the same, fire action immediately on rising edge
if ( macroButton [ b ] & & macroButton [ b ] = = macroLongPress [ b ] & & macroButton [ b ] = = macroDoublePress [ b ] ) {
if ( ! buttonPressedBefore [ b ] )
shortPressAction ( b ) ;
buttonPressedBefore [ b ] = true ;
buttonPressedTime [ b ] = now ; // continually update (for debouncing to work in release handler)
2023-08-23 12:50:46 +00:00
continue ;
2023-06-02 08:51:16 +00:00
}
2021-10-31 10:57:03 +00:00
2022-01-09 14:13:33 +00:00
if ( ! buttonPressedBefore [ b ] ) buttonPressedTime [ b ] = now ;
2021-05-20 17:54:07 +00:00
buttonPressedBefore [ b ] = true ;
2022-01-09 14:13:33 +00:00
if ( now - buttonPressedTime [ b ] > WLED_LONG_PRESS ) { //long press
2024-04-26 14:39:32 +00:00
if ( ! buttonLongPressed [ b ] ) {
buttonBriDirection = ! buttonBriDirection ; //toggle brightness direction on long press
longPressAction ( b ) ;
} else if ( b ) { //repeatable action (~5 times per s) on button > 0
2021-10-31 10:57:03 +00:00
longPressAction ( b ) ;
2024-04-26 14:39:32 +00:00
buttonPressedTime [ b ] = now - WLED_LONG_REPEATED_ACTION ; //200ms
2021-05-20 17:54:07 +00:00
}
2021-10-31 10:57:03 +00:00
buttonLongPressed [ b ] = true ;
2019-10-18 10:19:52 +00:00
}
2021-10-31 10:57:03 +00:00
2024-08-22 15:08:51 +00:00
} else if ( buttonPressedBefore [ b ] ) { //released
2022-01-09 14:13:33 +00:00
long dur = now - buttonPressedTime [ b ] ;
2023-06-02 08:51:16 +00:00
// released after rising-edge short press action
if ( macroButton [ b ] & & macroButton [ b ] = = macroLongPress [ b ] & & macroButton [ b ] = = macroDoublePress [ b ] ) {
if ( dur > WLED_DEBOUNCE_THRESHOLD ) buttonPressedBefore [ b ] = false ; // debounce, blocks button for 50 ms once it has been released
2023-08-23 12:50:46 +00:00
continue ;
2023-06-02 08:51:16 +00:00
}
if ( dur < WLED_DEBOUNCE_THRESHOLD ) { buttonPressedBefore [ b ] = false ; continue ; } // too short "press", debounce
2021-10-31 10:57:03 +00:00
bool doublePress = buttonWaitTime [ b ] ; //did we have a short press before?
2021-05-20 17:54:07 +00:00
buttonWaitTime [ b ] = 0 ;
2022-03-15 08:55:23 +00:00
if ( b = = 0 & & dur > WLED_LONG_AP ) { // long press on button 0 (when released)
if ( dur > WLED_LONG_FACTORY_RESET ) { // factory reset if pressed > 10 seconds
WLED_FS . format ( ) ;
2022-07-30 09:04:04 +00:00
# ifdef WLED_ADD_EEPROM_SUPPORT
2022-03-15 08:55:23 +00:00
clearEEPROM ( ) ;
2022-07-30 09:04:04 +00:00
# endif
2022-03-15 08:55:23 +00:00
doReboot = true ;
} else {
WLED : : instance ( ) . initAP ( true ) ;
}
2021-10-31 10:57:03 +00:00
} else if ( ! buttonLongPressed [ b ] ) { //short press
2022-02-20 21:24:11 +00:00
//NOTE: this interferes with double click handling in usermods so usermod needs to implement full button handling
if ( b ! = 1 & & ! macroDoublePress [ b ] ) { //don't wait for double press on buttons without a default action if no double press macro set
2022-01-21 20:24:49 +00:00
shortPressAction ( b ) ;
} else { //double press if less than 350 ms between current press and previous short press release (buttonWaitTime!=0)
2021-06-03 10:18:11 +00:00
if ( doublePress ) {
2021-10-31 10:57:03 +00:00
doublePressAction ( b ) ;
} else {
2022-01-09 14:13:33 +00:00
buttonWaitTime [ b ] = now ;
2021-10-31 10:57:03 +00:00
}
2022-01-21 20:24:49 +00:00
}
2021-05-20 17:54:07 +00:00
}
buttonPressedBefore [ b ] = false ;
buttonLongPressed [ b ] = false ;
2016-11-19 18:39:17 +00:00
}
2019-03-13 10:13:03 +00:00
2021-10-31 10:57:03 +00:00
//if 350ms elapsed since last short press release it is a short press
2022-01-09 14:13:33 +00:00
if ( buttonWaitTime [ b ] & & now - buttonWaitTime [ b ] > WLED_DOUBLE_PRESS & & ! buttonPressedBefore [ b ] ) {
2021-05-20 17:54:07 +00:00
buttonWaitTime [ b ] = 0 ;
shortPressAction ( b ) ;
}
2019-03-13 10:13:03 +00:00
}
2024-02-10 10:45:33 +00:00
if ( now - lastAnalogRead > ANALOG_BTN_READ_CYCLE ) {
lastAnalogRead = now ;
}
2019-03-13 10:13:03 +00:00
}
2024-06-23 12:09:18 +00:00
// handleIO() happens *after* handleTransitions() (see wled.cpp) which may change bri/briT but *before* strip.service()
// where actual LED painting occurrs
// this is important for relay control and in the event of turning off on-board LED
2019-03-13 10:13:03 +00:00
void handleIO ( )
{
handleButton ( ) ;
2023-01-06 08:24:29 +00:00
2024-06-23 12:09:18 +00:00
// if we want to control on-board LED (ESP8266) or relay we have to do it here as the final show() may not happen until
// next loop() cycle
if ( strip . getBrightness ( ) ) {
2019-03-13 10:13:03 +00:00
lastOnTime = millis ( ) ;
2024-06-23 12:09:18 +00:00
if ( offMode ) {
BusManager : : on ( ) ;
2021-01-16 23:20:31 +00:00
if ( rlyPin > = 0 ) {
2024-04-21 11:37:07 +00:00
pinMode ( rlyPin , rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT ) ;
2021-01-16 23:20:31 +00:00
digitalWrite ( rlyPin , rlyMde ) ;
}
2019-03-13 10:13:03 +00:00
offMode = false ;
}
2024-06-23 12:09:18 +00:00
} else if ( millis ( ) - lastOnTime > 600 & & ! strip . needsUpdate ( ) ) {
// for turning LED or relay off we need to wait until strip no longer needs updates (strip.trigger())
2021-01-16 23:20:31 +00:00
if ( ! offMode ) {
2024-06-23 12:09:18 +00:00
BusManager : : off ( ) ;
2021-01-16 23:20:31 +00:00
if ( rlyPin > = 0 ) {
2024-04-21 11:37:07 +00:00
pinMode ( rlyPin , rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT ) ;
2021-01-16 23:20:31 +00:00
digitalWrite ( rlyPin , ! rlyMde ) ;
}
2024-06-23 12:09:18 +00:00
offMode = true ;
2021-01-16 23:20:31 +00:00
}
2016-11-19 18:39:17 +00:00
}
2024-02-06 13:47:20 +00:00
}
2024-02-18 14:52:36 +00:00
void IRAM_ATTR touchButtonISR ( )
{
2024-02-21 17:38:34 +00:00
// used for ESP32 S2 and S3: nothing to do, ISR is just used to update registers of HAL driver
2024-04-07 20:12:01 +00:00
}