2019-01-07 11:38:47 +00:00
/*
2019-10-27 10:13:24 +00:00
support_button . ino - button support for Tasmota
2019-01-07 11:38:47 +00:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Federico Leoni and Theo Arends
2019-01-07 11:38:47 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2020-05-14 14:42:15 +01:00
# define BUTTON_V2
# ifdef BUTTON_V2
2019-01-07 11:38:47 +00:00
/*********************************************************************************************\
* Button support
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-05-14 14:42:15 +01:00
# define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1
2020-05-27 14:59:32 +01:00
# ifdef ESP32
# define TOUCH_PIN_THRESHOLD 12 // Smaller value will treated as button press
# define TOUCH_HIT_THRESHOLD 3 // successful hits to filter out noise
2020-11-28 11:46:17 +00:00
# endif // ESP32
2020-04-14 16:18:34 +01:00
2020-05-14 14:42:15 +01:00
const char kMultiPress [ ] PROGMEM =
" |SINGLE|DOUBLE|TRIPLE|QUAD|PENTA| " ;
2019-10-22 16:29:21 +01:00
2019-08-17 15:19:58 +01:00
struct BUTTON {
2020-10-28 10:48:57 +00:00
uint32_t debounce = 0 ; // Button debounce timer
2021-02-05 11:27:59 +00:00
uint32_t no_pullup_mask = 0 ; // key no pullup flag (1 = no pullup)
2021-04-26 12:56:44 +01:00
uint32_t pulldown_mask = 0 ; // key pulldown flag (1 = pulldown)
2021-02-05 11:27:59 +00:00
uint32_t inverted_mask = 0 ; // Key inverted flag (1 = inverted)
# ifdef ESP32
uint32_t touch_mask = 0 ; // Touch flag (1 = inverted)
# endif // ESP32
2019-08-17 15:19:58 +01:00
uint16_t hold_timer [ MAX_KEYS ] = { 0 } ; // Timer for button hold
uint16_t dual_code = 0 ; // Sonoff dual received code
2019-01-07 11:38:47 +00:00
2022-06-25 14:25:45 +01:00
uint8_t debounce_phase = 0 ; // 0 = regular iteration; 1 = read data for debouncing only
2021-02-05 11:27:59 +00:00
uint8_t last_state [ MAX_KEYS ] ; // Last button states
2022-06-25 14:25:45 +01:00
uint8_t last_state_between [ MAX_KEYS ] ; // Last button states at the half time read
2019-08-17 15:19:58 +01:00
uint8_t window_timer [ MAX_KEYS ] = { 0 } ; // Max time between button presses to record press count
uint8_t press_counter [ MAX_KEYS ] = { 0 } ; // Number of button presses within Button.window_timer
2019-01-07 11:38:47 +00:00
2019-08-17 15:19:58 +01:00
uint8_t dual_receive_count = 0 ; // Sonoff dual input flag
2020-05-31 15:28:02 +01:00
# ifdef ESP32
2020-05-27 14:59:32 +01:00
uint8_t touch_hits [ MAX_KEYS ] = { 0 } ; // Hits in a row to filter out noise
2020-11-28 11:46:17 +00:00
# endif // ESP32
2019-08-17 15:19:58 +01:00
uint8_t present = 0 ; // Number of buttons found flag
} Button ;
2019-01-07 11:38:47 +00:00
2020-05-30 12:50:22 +01:00
# ifdef ESP32
struct TOUCH_BUTTON {
uint8_t pin_threshold = TOUCH_PIN_THRESHOLD ;
uint8_t hit_threshold = TOUCH_HIT_THRESHOLD ;
2021-02-05 11:27:59 +00:00
uint32_t calibration = 0 ; // Bitfield
2020-05-30 12:50:22 +01:00
} TOUCH_BUTTON ;
2020-11-28 11:46:17 +00:00
# endif // ESP32
2020-05-30 12:50:22 +01:00
2019-01-07 11:38:47 +00:00
/********************************************************************************************/
2020-11-03 14:42:55 +00:00
void ButtonPullupFlag ( uint32_t button_bit ) {
2019-08-17 15:19:58 +01:00
bitSet ( Button . no_pullup_mask , button_bit ) ;
2019-01-07 11:38:47 +00:00
}
2021-04-26 12:56:44 +01:00
void ButtonPulldownFlag ( uint32_t button_bit ) {
bitSet ( Button . pulldown_mask , button_bit ) ;
}
2020-11-03 14:42:55 +00:00
void ButtonInvertFlag ( uint32_t button_bit ) {
2019-08-17 15:19:58 +01:00
bitSet ( Button . inverted_mask , button_bit ) ;
2019-01-27 13:54:28 +00:00
}
2020-11-03 14:42:55 +00:00
2020-05-27 14:59:32 +01:00
# ifdef ESP32
2020-11-03 14:42:55 +00:00
void ButtonTouchFlag ( uint32_t button_bit ) {
2020-05-27 14:59:32 +01:00
bitSet ( Button . touch_mask , button_bit ) ;
}
2020-11-28 11:46:17 +00:00
# endif // ESP32
2020-11-03 14:42:55 +00:00
void ButtonInit ( void ) {
2019-08-17 15:19:58 +01:00
Button . present = 0 ;
2020-05-31 15:28:02 +01:00
# ifdef ESP8266
2020-10-30 11:29:48 +00:00
if ( ( SONOFF_DUAL = = TasmotaGlobal . module_type ) | | ( CH4 = = TasmotaGlobal . module_type ) ) {
2020-05-31 15:28:02 +01:00
Button . present + + ;
}
# endif // ESP8266
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_KEYS ; i + + ) {
2021-02-05 11:27:59 +00:00
Button . last_state [ i ] = NOT_PRESSED ;
2022-06-25 14:25:45 +01:00
Button . last_state_between [ i ] = NOT_PRESSED ;
2020-04-27 11:54:07 +01:00
if ( PinUsed ( GPIO_KEY1 , i ) ) {
2019-08-17 15:19:58 +01:00
Button . present + + ;
2020-10-09 09:28:17 +01:00
# ifdef ESP8266
2020-04-26 16:33:27 +01:00
pinMode ( Pin ( GPIO_KEY1 , i ) , bitRead ( Button . no_pullup_mask , i ) ? INPUT : ( ( 16 = = Pin ( GPIO_KEY1 , i ) ) ? INPUT_PULLDOWN_16 : INPUT_PULLUP ) ) ;
2020-11-28 11:46:17 +00:00
# endif // ESP8266
# ifdef ESP32
2021-04-26 12:56:44 +01:00
pinMode ( Pin ( GPIO_KEY1 , i ) , bitRead ( Button . pulldown_mask , i ) ? INPUT_PULLDOWN : bitRead ( Button . no_pullup_mask , i ) ? INPUT : INPUT_PULLUP ) ;
2020-11-28 11:46:17 +00:00
# endif // ESP32
2019-01-07 11:38:47 +00:00
}
2020-10-08 17:27:12 +01:00
# ifdef USE_ADC
else if ( PinUsed ( GPIO_ADC_BUTTON , i ) | | PinUsed ( GPIO_ADC_BUTTON_INV , i ) ) {
2019-08-17 15:19:58 +01:00
Button . present + + ;
2019-05-13 14:56:01 +01:00
}
2020-10-08 17:27:12 +01:00
# endif // USE_ADC
2019-01-07 11:38:47 +00:00
}
}
2020-11-03 14:42:55 +00:00
uint8_t ButtonSerial ( uint8_t serial_in_byte ) {
2019-08-17 15:19:58 +01:00
if ( Button . dual_receive_count ) {
Button . dual_receive_count - - ;
if ( Button . dual_receive_count ) {
Button . dual_code = ( Button . dual_code < < 8 ) | serial_in_byte ;
2019-01-07 11:38:47 +00:00
serial_in_byte = 0 ;
} else {
if ( serial_in_byte ! = 0xA1 ) {
2019-08-17 15:19:58 +01:00
Button . dual_code = 0 ; // 0xA1 - End of Sonoff dual button code
2019-01-07 11:38:47 +00:00
}
}
}
if ( 0xA0 = = serial_in_byte ) { // 0xA0 - Start of Sonoff dual button code
serial_in_byte = 0 ;
2019-08-17 15:19:58 +01:00
Button . dual_code = 0 ;
Button . dual_receive_count = 3 ;
2019-01-07 11:38:47 +00:00
}
return serial_in_byte ;
}
/*********************************************************************************************\
* Button handler with single press only or multi - press and hold on all buttons
2019-06-05 14:26:42 +01:00
*
* ButtonDebounce ( 50 ) - Debounce time in mSec
2020-05-14 14:42:15 +01:00
* SetOption1 ( 0 ) - If set do not execute commands WifiConfig and Reset
* SetOption11 ( 0 ) - If set perform single press action on double press and reverse ( on two relay devices only )
2019-06-05 14:26:42 +01:00
* SetOption13 ( 0 ) - If set act on single press only
2020-05-14 14:42:15 +01:00
* SetOption73 ( 0 ) - Decouple button from relay and send just mqtt topic
2019-01-07 11:38:47 +00:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-11-03 14:42:55 +00:00
void ButtonHandler ( void ) {
2020-10-28 16:32:07 +00:00
if ( TasmotaGlobal . uptime < 4 ) { return ; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit
2019-01-07 11:38:47 +00:00
2019-06-05 14:26:42 +01:00
uint8_t hold_time_extent = IMMINENT_RESET_FACTOR ; // Extent hold time factor in case of iminnent Reset command
2021-06-11 17:14:12 +01:00
uint16_t loops_per_second = 1000 / Settings - > button_debounce ; // ButtonDebounce (50)
2019-01-07 11:38:47 +00:00
char scmnd [ 20 ] ;
2019-06-30 15:44:36 +01:00
for ( uint32_t button_index = 0 ; button_index < MAX_KEYS ; button_index + + ) {
2019-10-30 13:08:43 +00:00
uint8_t button = NOT_PRESSED ;
uint8_t button_present = 0 ;
2019-01-07 11:38:47 +00:00
2020-04-10 17:24:08 +01:00
# ifdef ESP8266
2020-10-30 11:29:48 +00:00
if ( ! button_index & & ( ( SONOFF_DUAL = = TasmotaGlobal . module_type ) | | ( CH4 = = TasmotaGlobal . module_type ) ) ) {
2019-01-07 11:38:47 +00:00
button_present = 1 ;
2019-08-17 15:19:58 +01:00
if ( Button . dual_code ) {
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X " ) , Button . dual_code ) ;
2019-01-07 11:38:47 +00:00
button = PRESSED ;
2019-08-17 15:19:58 +01:00
if ( 0xF500 = = Button . dual_code ) { // Button hold
2021-06-11 17:14:12 +01:00
Button . hold_timer [ button_index ] = ( loops_per_second * Settings - > param [ P_HOLD_TIME ] / 10 ) - 1 ; // SetOption32 (40)
2019-01-07 11:38:47 +00:00
hold_time_extent = 1 ;
}
2019-08-17 15:19:58 +01:00
Button . dual_code = 0 ;
2019-01-07 11:38:47 +00:00
}
2020-10-08 17:27:12 +01:00
} else
# endif // ESP8266
2020-05-27 14:59:32 +01:00
if ( PinUsed ( GPIO_KEY1 , button_index ) ) {
button_present = 1 ;
2020-10-08 17:27:12 +01:00
# ifdef ESP32
2021-11-30 13:55:45 +00:00
# ifndef CONFIG_IDF_TARGET_ESP32C3
2020-05-31 15:28:02 +01:00
if ( bitRead ( Button . touch_mask , button_index ) ) { // Touch
2020-05-27 14:59:32 +01:00
uint32_t _value = touchRead ( Pin ( GPIO_KEY1 , button_index ) ) ;
button = NOT_PRESSED ;
2020-05-31 15:28:02 +01:00
if ( _value ! = 0 ) { // Probably read-error
if ( _value < TOUCH_BUTTON . pin_threshold ) {
if ( + + Button . touch_hits [ button_index ] > TOUCH_BUTTON . hit_threshold ) {
if ( ! bitRead ( TOUCH_BUTTON . calibration , button_index + 1 ) ) {
button = PRESSED ;
}
2020-05-27 14:59:32 +01:00
}
2020-05-31 15:28:02 +01:00
} else {
Button . touch_hits [ button_index ] = 0 ;
2020-05-27 14:59:32 +01:00
}
2020-05-31 15:28:02 +01:00
} else {
Button . touch_hits [ button_index ] = 0 ;
2020-05-27 14:59:32 +01:00
}
2020-05-31 15:28:02 +01:00
if ( bitRead ( TOUCH_BUTTON . calibration , button_index + 1 ) ) {
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " PLOT: %u, %u, %u, " ) , button_index + 1 , _value , Button . touch_hits [ button_index ] ) ; // Button number (1..4), value, continuous hits under threshold
2020-05-31 15:28:02 +01:00
}
2020-10-08 17:27:12 +01:00
} else
2021-06-01 18:44:26 +01:00
# endif // not ESP32C3
2020-10-08 17:27:12 +01:00
# endif // ESP32
{ // Normal button
2020-05-27 14:59:32 +01:00
button = ( digitalRead ( Pin ( GPIO_KEY1 , button_index ) ) ! = bitRead ( Button . inverted_mask , button_index ) ) ;
}
}
2020-10-08 17:27:12 +01:00
# ifdef USE_ADC
else if ( PinUsed ( GPIO_ADC_BUTTON , button_index ) ) {
button_present = 1 ;
button = AdcGetButton ( Pin ( GPIO_ADC_BUTTON , button_index ) ) ;
}
else if ( PinUsed ( GPIO_ADC_BUTTON_INV , button_index ) ) {
button_present = 1 ;
button = AdcGetButton ( Pin ( GPIO_ADC_BUTTON_INV , button_index ) ) ;
}
# endif // USE_ADC
2022-06-25 14:25:45 +01:00
if ( Button . debounce_phase = = 1 ) {
// adjust values
Button . last_state_between [ button_index ] = button ;
continue ;
}
if ( button ! = Button . last_state_between [ button_index ] ) {
// no clean signal, just keep the previous one
button = Button . last_state [ button_index ] ;
}
2019-01-07 11:38:47 +00:00
if ( button_present ) {
XdrvMailbox . index = button_index ;
XdrvMailbox . payload = button ;
if ( XdrvCall ( FUNC_BUTTON_PRESSED ) ) {
// Serviced
}
2020-04-10 17:24:08 +01:00
# ifdef ESP8266
2020-10-30 11:29:48 +00:00
else if ( SONOFF_4CHPRO = = TasmotaGlobal . module_type ) {
2019-08-17 15:19:58 +01:00
if ( Button . hold_timer [ button_index ] ) { Button . hold_timer [ button_index ] - - ; }
2019-01-07 11:38:47 +00:00
2019-01-28 13:08:33 +00:00
bool button_pressed = false ;
2019-08-17 15:19:58 +01:00
if ( ( PRESSED = = button ) & & ( NOT_PRESSED = = Button . last_state [ button_index ] ) ) {
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_BUTTON " %d " D_LEVEL_10 ) , button_index + 1 ) ;
2019-08-17 15:19:58 +01:00
Button . hold_timer [ button_index ] = loops_per_second ;
2019-01-07 11:38:47 +00:00
button_pressed = true ;
}
2019-08-17 15:19:58 +01:00
if ( ( NOT_PRESSED = = button ) & & ( PRESSED = = Button . last_state [ button_index ] ) ) {
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_BUTTON " %d " D_LEVEL_01 ) , button_index + 1 ) ;
2019-08-17 15:19:58 +01:00
if ( ! Button . hold_timer [ button_index ] ) { button_pressed = true ; } // Do not allow within 1 second
2019-01-07 11:38:47 +00:00
}
if ( button_pressed ) {
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag3 . mqtt_buttons ) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic
2020-05-14 14:42:15 +01:00
if ( ! SendKey ( KEY_BUTTON , button_index + 1 , POWER_TOGGLE ) ) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower ( button_index + 1 , POWER_TOGGLE , SRC_BUTTON ) ; // Execute Toggle command internally
}
} else {
2020-05-31 15:28:02 +01:00
MqttButtonTopic ( button_index + 1 , 1 , 0 ) ; // SetOption73 (0) - Decouple button from relay and send just mqtt topic
2019-01-07 11:38:47 +00:00
}
}
}
2020-04-10 17:24:08 +01:00
# endif // ESP8266
2019-01-07 11:38:47 +00:00
else {
2019-08-17 15:19:58 +01:00
if ( ( PRESSED = = button ) & & ( NOT_PRESSED = = Button . last_state [ button_index ] ) ) {
2020-05-14 14:42:15 +01:00
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . button_single ) { // SetOption13 (0) - Allow only single button press for immediate action,
if ( ! Settings - > flag3 . mqtt_buttons ) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_BUTTON " %d " D_IMMEDIATE ) , button_index + 1 ) ;
2020-05-14 14:42:15 +01:00
if ( ! SendKey ( KEY_BUTTON , button_index + 1 , POWER_TOGGLE ) ) { // Execute Toggle command via MQTT if ButtonTopic is set
ExecuteCommandPower ( button_index + 1 , POWER_TOGGLE , SRC_BUTTON ) ; // Execute Toggle command internally
}
} else {
MqttButtonTopic ( button_index + 1 , 1 , 0 ) ; // SetOption73 1 - Decouple button from relay and send just mqtt topic
2019-01-07 11:38:47 +00:00
}
} else {
2019-08-17 15:19:58 +01:00
Button . press_counter [ button_index ] = ( Button . window_timer [ button_index ] ) ? Button . press_counter [ button_index ] + 1 : 1 ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_BUTTON " %d " D_MULTI_PRESS " %d " ) , button_index + 1 , Button . press_counter [ button_index ] ) ;
2019-08-17 15:19:58 +01:00
Button . window_timer [ button_index ] = loops_per_second / 2 ; // 0.5 second multi press window
2019-01-07 11:38:47 +00:00
}
2020-10-29 11:39:44 +00:00
TasmotaGlobal . blinks = 201 ;
2019-01-07 11:38:47 +00:00
}
if ( NOT_PRESSED = = button ) {
2019-08-17 15:19:58 +01:00
Button . hold_timer [ button_index ] = 0 ;
2019-01-07 11:38:47 +00:00
} else {
2019-08-17 15:19:58 +01:00
Button . hold_timer [ button_index ] + + ;
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . button_single ) { // SetOption13 (0) - Allow only single button press for immediate action
if ( Button . hold_timer [ button_index ] = = loops_per_second * hold_time_extent * Settings - > param [ P_HOLD_TIME ] / 10 ) { // SetOption32 (40) - Button held for factor times longer
2019-01-07 11:38:47 +00:00
snprintf_P ( scmnd , sizeof ( scmnd ) , PSTR ( D_CMND_SETOPTION " 13 0 " ) ) ; // Disable single press only
ExecuteCommand ( scmnd , SRC_BUTTON ) ;
}
} else {
2021-06-11 17:14:12 +01:00
if ( Button . hold_timer [ button_index ] = = loops_per_second * Settings - > param [ P_HOLD_TIME ] / 10 ) { // SetOption32 (40) - Button hold
2020-05-14 14:42:15 +01:00
Button . press_counter [ button_index ] = 0 ;
2021-06-11 17:14:12 +01:00
if ( Settings - > flag3 . mqtt_buttons ) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic
2020-05-14 14:42:15 +01:00
MqttButtonTopic ( button_index + 1 , 3 , 1 ) ;
} else {
2019-09-04 11:20:04 +01:00
SendKey ( KEY_BUTTON , button_index + 1 , POWER_HOLD ) ; // Execute Hold command via MQTT if ButtonTopic is set
2019-01-07 11:38:47 +00:00
}
} else {
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . button_restrict ) { // SetOption1 (0) - Control button multipress
if ( Settings - > param [ P_HOLD_IGNORE ] > 0 ) { // SetOption40 (0) - Do not ignore button hold
if ( Button . hold_timer [ button_index ] > loops_per_second * Settings - > param [ P_HOLD_IGNORE ] / 10 ) {
2021-01-17 16:01:52 +00:00
Button . hold_timer [ button_index ] = 0 ; // Reset button hold counter to stay below hold trigger
Button . press_counter [ button_index ] = 0 ; // Discard button press to disable functionality
}
}
} else {
2021-06-11 17:14:12 +01:00
if ( ( Button . hold_timer [ button_index ] = = loops_per_second * hold_time_extent * Settings - > param [ P_HOLD_TIME ] / 10 ) ) { // SetOption32 (40) - Button held for factor times longer
2020-05-14 14:42:15 +01:00
Button . press_counter [ button_index ] = 0 ;
snprintf_P ( scmnd , sizeof ( scmnd ) , PSTR ( D_CMND_RESET " 1 " ) ) ;
ExecuteCommand ( scmnd , SRC_BUTTON ) ;
}
2019-01-07 11:38:47 +00:00
}
}
}
}
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag . button_single ) { // SetOption13 (0) - Allow multi-press
2019-08-17 15:19:58 +01:00
if ( Button . window_timer [ button_index ] ) {
Button . window_timer [ button_index ] - - ;
2019-01-07 11:38:47 +00:00
} else {
2020-10-29 11:21:24 +00:00
if ( ! TasmotaGlobal . restart_flag & & ! Button . hold_timer [ button_index ] & & ( Button . press_counter [ button_index ] > 0 ) & & ( Button . press_counter [ button_index ] < 7 ) ) {
2020-05-14 14:42:15 +01:00
2019-01-28 13:08:33 +00:00
bool single_press = false ;
2020-05-31 15:28:02 +01:00
if ( Button . press_counter [ button_index ] < 3 ) { // Single or Double press
2020-04-10 17:24:08 +01:00
# ifdef ESP8266
2020-10-30 11:29:48 +00:00
if ( ( SONOFF_DUAL_R2 = = TasmotaGlobal . module_type ) | | ( SONOFF_DUAL = = TasmotaGlobal . module_type ) | | ( CH4 = = TasmotaGlobal . module_type ) ) {
2019-01-07 11:38:47 +00:00
single_press = true ;
2020-04-10 17:24:08 +01:00
} else
# endif // ESP8266
{
2021-06-11 17:14:12 +01:00
single_press = ( Settings - > flag . button_swap + 1 = = Button . press_counter [ button_index ] ) ; // SetOption11 (0)
2020-10-30 11:29:48 +00:00
if ( ( 1 = = Button . present ) & & ( 2 = = TasmotaGlobal . devices_present ) ) { // Single Button with two devices only
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . button_swap ) { // SetOption11 (0)
2019-08-17 15:19:58 +01:00
Button . press_counter [ button_index ] = ( single_press ) ? 1 : 2 ;
2019-06-06 12:09:06 +01:00
}
2019-06-05 14:26:42 +01:00
}
2019-01-07 11:38:47 +00:00
}
}
2021-11-30 13:55:45 +00:00
XdrvMailbox . index = button_index ;
XdrvMailbox . payload = Button . press_counter [ button_index ] ;
if ( XdrvCall ( FUNC_BUTTON_MULTI_PRESSED ) ) {
// Serviced
} else
2020-07-02 17:13:14 +01:00
# ifdef ROTARY_V1
2020-07-12 17:53:57 +01:00
if ( ! RotaryButtonPressed ( button_index ) ) {
2019-06-16 15:43:23 +01:00
# endif
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag3 . mqtt_buttons & & single_press & & SendKey ( KEY_BUTTON , button_index + Button . press_counter [ button_index ] , POWER_TOGGLE ) ) { // Execute Toggle command via MQTT if ButtonTopic is set
2019-01-15 15:11:42 +00:00
// Success
} else {
2020-05-14 14:42:15 +01:00
if ( Button . press_counter [ button_index ] < 6 ) { // Single to Penta press
2021-06-30 13:36:15 +01:00
// if (WifiState() > WIFI_RESTART) { // Wifimanager active
// TasmotaGlobal.restart_flag = 1;
// }
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag3 . mqtt_buttons ) { // SetOption73 - Detach buttons from relays and enable MQTT action state for multipress
2020-05-31 15:28:02 +01:00
if ( Button . press_counter [ button_index ] = = 1 ) { // By default first press always send a TOGGLE (2)
2020-05-14 14:42:15 +01:00
ExecuteCommandPower ( button_index + Button . press_counter [ button_index ] , POWER_TOGGLE , SRC_BUTTON ) ;
} else {
SendKey ( KEY_BUTTON , button_index + 1 , Button . press_counter [ button_index ] + 9 ) ; // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules
2020-05-31 15:28:02 +01:00
if ( 0 = = button_index ) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules
bool valid_relay = PinUsed ( GPIO_REL1 , Button . press_counter [ button_index ] - 1 ) ;
# ifdef ESP8266
2020-10-30 11:29:48 +00:00
if ( ( SONOFF_DUAL = = TasmotaGlobal . module_type ) | | ( CH4 = = TasmotaGlobal . module_type ) ) {
valid_relay = ( Button . press_counter [ button_index ] < = TasmotaGlobal . devices_present ) ;
2020-05-31 15:28:02 +01:00
}
# endif // ESP8266
if ( ( Button . press_counter [ button_index ] > 1 ) & & valid_relay & & ( Button . press_counter [ button_index ] < = MAX_RELAY_BUTTON1 ) ) {
2020-05-14 14:42:15 +01:00
ExecuteCommandPower ( button_index + Button . press_counter [ button_index ] , POWER_TOGGLE , SRC_BUTTON ) ; // Execute Toggle command internally
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Relay%d found on GPIO%d"), Button.press_counter[button_index], Pin(GPIO_REL1, Button.press_counter[button_index]-1));
2020-05-14 14:42:15 +01:00
}
}
}
}
} else { // 6 press start wificonfig 2
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag . button_restrict ) { // SetOption1 - Control button multipress
2020-05-14 14:42:15 +01:00
snprintf_P ( scmnd , sizeof ( scmnd ) , PSTR ( D_CMND_WIFICONFIG " 2 " ) ) ;
2019-01-15 00:45:19 +00:00
ExecuteCommand ( scmnd , SRC_BUTTON ) ;
}
2019-01-07 11:38:47 +00:00
}
2021-06-11 17:14:12 +01:00
if ( Settings - > flag3 . mqtt_buttons ) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic
2020-05-14 14:42:15 +01:00
if ( Button . press_counter [ button_index ] > = 1 & & Button . press_counter [ button_index ] < = 5 ) {
MqttButtonTopic ( button_index + 1 , Button . press_counter [ button_index ] , 0 ) ;
}
}
2019-01-07 11:38:47 +00:00
}
2020-07-02 17:13:14 +01:00
# ifdef ROTARY_V1
2019-01-07 11:38:47 +00:00
}
2019-06-16 15:43:23 +01:00
# endif
2019-08-17 15:19:58 +01:00
Button . press_counter [ button_index ] = 0 ;
2019-01-07 11:38:47 +00:00
}
}
}
2020-05-14 14:42:15 +01:00
2019-01-07 11:38:47 +00:00
}
}
2019-08-17 15:19:58 +01:00
Button . last_state [ button_index ] = button ;
2019-01-07 11:38:47 +00:00
}
2022-06-25 14:25:45 +01:00
Button . debounce_phase = ( Button . debounce_phase + 1 ) & 1 ;
2019-01-07 11:38:47 +00:00
}
2020-11-03 14:42:55 +00:00
/*
void MqttButtonTopic ( uint8_t button_id , uint8_t action , uint8_t hold ) {
2020-05-14 14:42:15 +01:00
char scommand [ CMDSZ ] ;
char stopic [ TOPSZ ] ;
char mqttstate [ 7 ] ;
SendKey ( KEY_BUTTON , button_id , ( hold ) ? 3 : action + 9 ) ;
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag . hass_discovery ) {
2020-05-14 14:42:15 +01:00
GetTextIndexed ( mqttstate , sizeof ( mqttstate ) , action , kMultiPress ) ;
snprintf_P ( scommand , sizeof ( scommand ) , PSTR ( " BUTTON%d " ) , button_id ) ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( stopic , STAT , TasmotaGlobal . mqtt_topic , scommand ) ;
2020-05-14 14:42:15 +01:00
Response_P ( S_JSON_COMMAND_SVALUE , " ACTION " , ( hold ) ? SettingsText ( SET_STATE_TXT4 ) : mqttstate ) ;
MqttPublish ( stopic ) ;
}
}
2020-11-03 14:42:55 +00:00
*/
void MqttButtonTopic ( uint32_t button_id , uint32_t action , uint32_t hold ) {
SendKey ( KEY_BUTTON , button_id , ( hold ) ? 3 : action + 9 ) ;
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag . hass_discovery ) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
2020-11-03 15:05:57 +00:00
char scommand [ 10 ] ;
2020-11-03 15:24:49 +00:00
snprintf_P ( scommand , sizeof ( scommand ) , PSTR ( D_JSON_BUTTON " %d " ) , button_id ) ;
char mqttstate [ 7 ] ;
Response_P ( S_JSON_SVALUE_ACTION_SVALUE , scommand , ( hold ) ? SettingsText ( SET_STATE_TXT4 ) : GetTextIndexed ( mqttstate , sizeof ( mqttstate ) , action , kMultiPress ) ) ;
2020-11-03 15:05:57 +00:00
MqttPublishPrefixTopicRulesProcess_P ( RESULT_OR_STAT , scommand ) ;
2020-11-03 14:42:55 +00:00
}
}
2020-05-14 14:42:15 +01:00
2020-11-03 14:42:55 +00:00
void ButtonLoop ( void ) {
2019-08-17 15:19:58 +01:00
if ( Button . present ) {
if ( TimeReached ( Button . debounce ) ) {
2022-06-25 14:25:45 +01:00
SetNextTimeInterval ( Button . debounce , Settings - > button_debounce / 2 ) ;
2019-01-07 11:38:47 +00:00
ButtonHandler ( ) ;
}
}
}
2021-06-01 18:44:26 +01:00
# endif // BUTTON_V2