2018-12-28 15:35:19 +00:00
/*
2019-10-27 10:13:24 +00:00
support_switch . ino - switch support for Tasmota
2018-12-28 15:35:19 +00:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Theo Arends
2018-12-28 15:35:19 +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-03-14 12:13:33 +00:00
# define SWITCH_V3
# ifdef SWITCH_V3
2018-12-28 15:35:19 +00:00
/*********************************************************************************************\
* Switch support with input filter
*
* Inspired by ( https : //github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/master/olimex/user/user_switch2.c)
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-12-26 13:51:24 +00:00
const uint8_t SWITCH_PROBE_INTERVAL = 10 ; // Time in milliseconds between switch input probe
const uint8_t SWITCH_FAST_PROBE_INTERVAL = 2 ; // Time in milliseconds between switch input probe for AC detection
2020-06-02 21:17:20 +01:00
const uint8_t AC_PERIOD = ( 20 + SWITCH_FAST_PROBE_INTERVAL - 1 ) / SWITCH_FAST_PROBE_INTERVAL ; // Duration of an AC wave in probe intervals
2018-12-28 15:35:19 +00:00
2020-08-09 14:31:37 +01:00
// Switch Mode definietions
# define SM_TIMER_MASK 0x3F
# define SM_NO_TIMER_MASK 0xFF
# define SM_FIRST_PRESS 0x40
# define SM_SECOND_PRESS 0x80
2020-11-02 23:44:07 +00:00
# define POWER_NONE 99
const char kSwitchPressStates [ ] PROGMEM =
2021-08-29 23:13:40 +01:00
" ||||POWER_INCREMENT|POWER_INV|POWER_CLEAR|POWER_RELEASE|POWER_100||POWER_DELAYED " ;
2020-08-09 14:31:37 +01:00
2018-12-28 15:35:19 +00:00
# include <Ticker.h>
Ticker TickerSwitch ;
2019-08-17 15:19:58 +01:00
struct SWITCH {
2020-10-28 10:48:57 +00:00
uint32_t debounce = 0 ; // Switch debounce timer
2021-02-05 10:58:24 +00:00
uint32_t no_pullup_mask = 0 ; // Switch pull-up bitmask flags
2021-04-27 10:36:10 +01:00
uint32_t pulldown_mask = 0 ; // Switch pull-down bitmask flags
2019-08-17 15:19:58 +01:00
uint8_t state [ MAX_SWITCHES ] = { 0 } ;
uint8_t last_state [ MAX_SWITCHES ] ; // Last wall switch states
uint8_t hold_timer [ MAX_SWITCHES ] = { 0 } ; // Timer for wallswitch push button hold
uint8_t virtual_state [ MAX_SWITCHES ] ; // Virtual switch states
2020-06-02 21:17:20 +01:00
uint8_t first_change = 0 ;
2019-08-17 15:19:58 +01:00
uint8_t present = 0 ;
} Switch ;
2018-12-28 15:35:19 +00:00
/********************************************************************************************/
2020-11-03 14:42:55 +00:00
void SwitchPullupFlag ( uint32 switch_bit ) {
2019-08-17 15:19:58 +01:00
bitSet ( Switch . no_pullup_mask , switch_bit ) ;
2018-12-28 15:35:19 +00:00
}
2021-04-27 10:36:10 +01:00
void SwitchPulldownFlag ( uint32 switch_bit ) {
bitSet ( Switch . pulldown_mask , switch_bit ) ;
}
2020-11-03 14:42:55 +00:00
void SwitchSetVirtual ( uint32_t index , uint32_t state ) {
2020-02-06 13:53:35 +00:00
Switch . virtual_state [ index ] = state ;
2018-12-28 15:35:19 +00:00
}
2020-11-03 14:42:55 +00:00
uint8_t SwitchGetVirtual ( uint32_t index ) {
2020-02-06 13:53:35 +00:00
return Switch . virtual_state [ index ] ;
2018-12-28 15:35:19 +00:00
}
2020-11-03 14:42:55 +00:00
uint8_t SwitchLastState ( uint32_t index ) {
2020-02-06 13:53:35 +00:00
return Switch . last_state [ index ] ;
}
2020-11-03 14:42:55 +00:00
bool SwitchState ( uint32_t index ) {
2021-06-11 17:14:12 +01:00
uint32_t switchmode = Settings - > switchmode [ index ] ;
2020-02-06 13:53:35 +00:00
return ( ( FOLLOW_INV = = switchmode ) | |
( PUSHBUTTON_INV = = switchmode ) | |
( PUSHBUTTONHOLD_INV = = switchmode ) | |
( FOLLOWMULTI_INV = = switchmode ) | |
2020-03-14 13:54:11 +00:00
( PUSHHOLDMULTI_INV = = switchmode ) | |
( PUSHON_INV = = switchmode )
2020-02-06 13:53:35 +00:00
) ^ Switch . last_state [ index ] ;
2018-12-28 15:35:19 +00:00
}
/*********************************************************************************************/
2020-11-03 14:42:55 +00:00
void SwitchProbe ( void ) {
if ( TasmotaGlobal . uptime < 4 ) { return ; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit
2019-01-07 09:15:00 +00:00
2020-11-03 14:42:55 +00:00
uint32_t state_filter ;
uint32_t first_change = Switch . first_change ;
2021-06-11 17:14:12 +01:00
uint32_t debounce_flags = Settings - > switch_debounce % 10 ;
2020-11-03 14:42:55 +00:00
bool force_high = ( debounce_flags & 1 ) ; // 51, 101, 151 etc
bool force_low = ( debounce_flags & 2 ) ; // 52, 102, 152 etc
bool ac_detect = ( debounce_flags = = 9 ) ;
2020-06-02 21:17:20 +01:00
if ( ac_detect ) {
2021-06-11 17:14:12 +01:00
if ( Settings - > switch_debounce < 2 * AC_PERIOD * SWITCH_FAST_PROBE_INTERVAL + 9 ) {
2020-06-02 21:17:20 +01:00
state_filter = 2 * AC_PERIOD ;
2021-06-11 17:14:12 +01:00
} else if ( Settings - > switch_debounce > ( 0x7f - 2 * AC_PERIOD ) * SWITCH_FAST_PROBE_INTERVAL ) {
2020-06-02 21:17:20 +01:00
state_filter = 0x7f ;
} else {
2021-06-11 17:14:12 +01:00
state_filter = ( Settings - > switch_debounce - 9 ) / SWITCH_FAST_PROBE_INTERVAL ;
2020-06-02 21:17:20 +01:00
}
} else {
2021-06-11 17:14:12 +01:00
state_filter = Settings - > switch_debounce / SWITCH_PROBE_INTERVAL ; // 5, 10, 15
2020-06-02 21:17:20 +01:00
}
2018-12-30 13:04:32 +00:00
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_SWITCHES ; i + + ) {
2020-12-26 13:51:24 +00:00
if ( ! PinUsed ( GPIO_SWT1 , i ) ) { continue ; }
// Olimex user_switch2.c code to fix 50Hz induced pulses
if ( 1 = = digitalRead ( Pin ( GPIO_SWT1 , i ) ) ) {
if ( ac_detect ) { // Enabled with SwitchDebounce x9
Switch . state [ i ] | = 0x80 ;
if ( Switch . state [ i ] > 0x80 ) {
Switch . state [ i ] - - ;
if ( 0x80 = = Switch . state [ i ] ) {
Switch . virtual_state [ i ] = 0 ;
Switch . first_change = false ;
2018-12-30 13:04:32 +00:00
}
2020-12-26 13:51:24 +00:00
}
} else {
2018-12-30 13:04:32 +00:00
2020-12-26 13:51:24 +00:00
if ( force_high ) { // Enabled with SwitchDebounce x1
if ( 1 = = Switch . virtual_state [ i ] ) {
Switch . state [ i ] = state_filter ; // With noisy input keep current state 1 unless constant 0
2020-06-02 21:17:20 +01:00
}
2020-12-26 13:51:24 +00:00
}
2020-06-02 21:17:20 +01:00
2020-12-26 13:51:24 +00:00
if ( Switch . state [ i ] < state_filter ) {
Switch . state [ i ] + + ;
if ( state_filter = = Switch . state [ i ] ) {
Switch . virtual_state [ i ] = 1 ;
2018-12-28 15:35:19 +00:00
}
2019-01-07 09:15:00 +00:00
}
2020-12-26 13:51:24 +00:00
}
} else {
2018-12-30 13:04:32 +00:00
2020-12-26 13:51:24 +00:00
if ( ac_detect ) { // Enabled with SwitchDebounce x9
/*
* Moes MS - 104 B and similar devices using an AC detection circuitry
* on their switch inputs generating an ~ 4 ms long low pulse every
* AC wave . We start the time measurement on the falling edge .
*
* state : bit7 : previous state , bit6 . .0 : counter
*/
if ( Switch . state [ i ] & 0x80 ) {
Switch . state [ i ] & = 0x7f ;
if ( Switch . state [ i ] < state_filter - 2 * AC_PERIOD ) {
Switch . state [ i ] + = 2 * AC_PERIOD ;
2020-06-02 21:17:20 +01:00
} else {
2020-12-26 13:51:24 +00:00
Switch . state [ i ] = state_filter ;
Switch . virtual_state [ i ] = 1 ;
if ( first_change ) {
Switch . last_state [ i ] = 1 ;
Switch . first_change = false ;
2020-06-02 21:17:20 +01:00
}
2018-12-30 13:04:32 +00:00
}
2020-06-02 21:17:20 +01:00
} else {
2020-12-26 13:51:24 +00:00
if ( Switch . state [ i ] > 0x00 ) {
2020-06-02 21:17:20 +01:00
Switch . state [ i ] - - ;
2020-12-26 13:51:24 +00:00
if ( 0x00 = = Switch . state [ i ] ) {
2020-06-02 21:17:20 +01:00
Switch . virtual_state [ i ] = 0 ;
2020-12-26 13:51:24 +00:00
Switch . first_change = false ;
2020-06-02 21:17:20 +01:00
}
2018-12-28 15:35:19 +00:00
}
}
2020-12-26 13:51:24 +00:00
} else {
if ( force_low ) { // Enabled with SwitchDebounce x2
if ( 0 = = Switch . virtual_state [ i ] ) {
Switch . state [ i ] = 0 ; // With noisy input keep current state 0 unless constant 1
}
}
if ( Switch . state [ i ] > 0 ) {
Switch . state [ i ] - - ;
if ( 0 = = Switch . state [ i ] ) {
Switch . virtual_state [ i ] = 0 ;
}
}
2018-12-28 15:35:19 +00:00
}
}
}
}
2020-11-03 14:42:55 +00:00
void SwitchInit ( void ) {
2021-06-11 17:14:12 +01:00
bool ac_detect = ( Settings - > switch_debounce % 10 = = 9 ) ;
2020-06-02 21:17:20 +01:00
2019-08-17 15:19:58 +01:00
Switch . present = 0 ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_SWITCHES ; i + + ) {
2022-08-27 11:28:34 +01:00
Switch . last_state [ i ] = NOT_PRESSED ; // Init global to virtual switch state;
2020-04-27 11:54:07 +01:00
if ( PinUsed ( GPIO_SWT1 , i ) ) {
2019-08-17 15:19:58 +01:00
Switch . present + + ;
2020-10-09 09:28:17 +01:00
# ifdef ESP8266
2020-04-26 16:33:27 +01:00
pinMode ( Pin ( GPIO_SWT1 , i ) , bitRead ( Switch . no_pullup_mask , i ) ? INPUT : ( ( 16 = = Pin ( GPIO_SWT1 , i ) ) ? INPUT_PULLDOWN_16 : INPUT_PULLUP ) ) ;
2020-11-28 11:46:17 +00:00
# endif // ESP8266
# ifdef ESP32
2021-04-27 10:36:10 +01:00
pinMode ( Pin ( GPIO_SWT1 , i ) , bitRead ( Switch . pulldown_mask , i ) ? INPUT_PULLDOWN : bitRead ( Switch . no_pullup_mask , i ) ? INPUT : INPUT_PULLUP ) ;
2020-11-28 11:46:17 +00:00
# endif // ESP32
2020-06-02 21:17:20 +01:00
if ( ac_detect ) {
Switch . state [ i ] = 0x80 + 2 * AC_PERIOD ;
Switch . last_state [ i ] = 0 ; // Will set later in the debouncing code
} else {
Switch . last_state [ i ] = digitalRead ( Pin ( GPIO_SWT1 , i ) ) ; // Set global now so doesn't change the saved power state on first switch check
}
2018-12-28 15:35:19 +00:00
}
2019-08-17 15:19:58 +01:00
Switch . virtual_state [ i ] = Switch . last_state [ i ] ;
2018-12-28 15:35:19 +00:00
}
2020-06-02 21:17:20 +01:00
if ( Switch . present ) {
2020-12-26 13:51:24 +00:00
Switch . first_change = true ;
TickerSwitch . attach_ms ( ( ac_detect ) ? SWITCH_FAST_PROBE_INTERVAL : SWITCH_PROBE_INTERVAL , SwitchProbe ) ;
2020-06-02 21:17:20 +01:00
}
2018-12-28 15:35:19 +00:00
}
/*********************************************************************************************\
* Switch handler
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-11-03 14:42:55 +00:00
void SwitchHandler ( uint32_t mode ) {
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
2021-06-11 17:14:12 +01:00
uint32_t loops_per_second = 1000 / Settings - > switch_debounce ;
2018-12-28 15:35:19 +00:00
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_SWITCHES ; i + + ) {
2020-04-27 11:54:07 +01:00
if ( PinUsed ( GPIO_SWT1 , i ) | | ( mode ) ) {
2020-11-03 13:34:02 +00:00
uint32_t button = Switch . virtual_state [ i ] ;
uint32_t switchflag = POWER_TOGGLE + 1 ;
2020-11-03 14:42:55 +00:00
uint32_t mqtt_action = POWER_NONE ;
2021-06-11 17:14:12 +01:00
uint32_t switchmode = Settings - > switchmode [ i ] ;
2018-12-28 15:35:19 +00:00
2021-08-29 22:03:14 +01:00
if ( Switch . hold_timer [ i ] & ( ( ( switchmode = = PUSHHOLDMULTI ) | ( switchmode = = PUSHHOLDMULTI_INV ) ) ? SM_TIMER_MASK : SM_NO_TIMER_MASK ) ) {
2019-08-17 15:19:58 +01:00
Switch . hold_timer [ i ] - - ;
2021-06-11 17:14:12 +01:00
if ( ( Switch . hold_timer [ i ] & SM_TIMER_MASK ) = = loops_per_second * Settings - > param [ P_HOLD_TIME ] / 25 ) {
2021-08-29 22:03:14 +01:00
if ( ( switchmode = = PUSHHOLDMULTI ) | ( switchmode = = PUSHHOLDMULTI_INV ) ) {
if ( ( ( switchmode = = PUSHHOLDMULTI ) & ( NOT_PRESSED = = Switch . last_state [ i ] ) ) | ( ( switchmode = = PUSHHOLDMULTI_INV ) & ( PRESSED = = Switch . last_state [ i ] ) ) ) {
SendKey ( KEY_SWITCH , i + 1 , POWER_INCREMENT ) ; // Execute command via MQTT
}
else if ( ( Switch . hold_timer [ i ] & ~ SM_TIMER_MASK ) = = SM_FIRST_PRESS ) {
2021-08-29 23:13:40 +01:00
SendKey ( KEY_SWITCH , i + 1 , POWER_DELAYED ) ; // Execute command via MQTT
mqtt_action = POWER_DELAYED ;
2021-08-29 22:03:14 +01:00
Switch . hold_timer [ i ] = 0 ;
}
2020-05-19 14:52:10 +01:00
}
}
2021-08-29 22:03:14 +01:00
if ( 0 = = ( Switch . hold_timer [ i ] & ( ( ( switchmode = = PUSHHOLDMULTI ) | ( switchmode = = PUSHHOLDMULTI_INV ) ) ? SM_TIMER_MASK : SM_NO_TIMER_MASK ) ) ) {
2021-02-05 10:58:24 +00:00
switch ( switchmode ) {
2020-01-15 12:05:00 +00:00
case TOGGLEMULTI :
2020-11-03 14:42:55 +00:00
switchflag = POWER_TOGGLE ; // Toggle after hold
2020-01-15 12:05:00 +00:00
break ;
case FOLLOWMULTI :
2020-11-03 14:42:55 +00:00
switchflag = button & 1 ; // Follow wall switch state after hold
2020-01-15 12:05:00 +00:00
break ;
case FOLLOWMULTI_INV :
2020-11-03 14:42:55 +00:00
switchflag = ~ button & 1 ; // Follow inverted wall switch state after hold
2020-01-15 12:05:00 +00:00
break ;
2020-01-25 10:22:28 +00:00
case PUSHHOLDMULTI :
2020-03-14 12:13:33 +00:00
if ( NOT_PRESSED = = button ) {
2021-06-11 17:14:12 +01:00
Switch . hold_timer [ i ] = loops_per_second * Settings - > param [ P_HOLD_TIME ] / 25 ;
2020-01-28 14:10:23 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_INCREMENT ) ; // Execute command via MQTT
2020-11-03 14:42:55 +00:00
mqtt_action = POWER_INCREMENT ;
2020-03-14 12:13:33 +00:00
} else {
2020-08-04 21:53:44 +01:00
Switch . hold_timer [ i ] = 0 ;
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_CLEAR ) ; // Execute command via MQTT
mqtt_action = POWER_CLEAR ;
2020-03-14 12:13:33 +00:00
}
2020-02-06 13:53:35 +00:00
break ;
case PUSHHOLDMULTI_INV :
2020-03-14 12:13:33 +00:00
if ( PRESSED = = button ) {
2021-06-11 17:14:12 +01:00
Switch . hold_timer [ i ] = loops_per_second * Settings - > param [ P_HOLD_TIME ] / 25 ;
2020-01-28 14:10:23 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_INCREMENT ) ; // Execute command via MQTT
2020-11-03 14:42:55 +00:00
mqtt_action = POWER_INCREMENT ;
2020-03-14 12:13:33 +00:00
} else {
2020-08-04 21:53:44 +01:00
Switch . hold_timer [ i ] = 0 ;
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_CLEAR ) ; // Execute command via MQTT
mqtt_action = POWER_CLEAR ;
2020-03-14 12:13:33 +00:00
}
2020-02-06 13:53:35 +00:00
break ;
2020-01-15 12:05:00 +00:00
default :
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_HOLD ) ; // Execute command via MQTT
mqtt_action = POWER_HOLD ;
2020-01-15 12:05:00 +00:00
break ;
}
2018-12-28 15:35:19 +00:00
}
}
2020-03-14 12:13:33 +00:00
if ( button ! = Switch . last_state [ i ] ) { // This implies if ((PRESSED == button) then (NOT_PRESSED == Switch.last_state[i]))
2021-02-05 10:58:24 +00:00
switch ( switchmode ) {
2018-12-28 15:35:19 +00:00
case TOGGLE :
2020-01-15 12:05:00 +00:00
case PUSHBUTTON_TOGGLE :
2020-11-03 14:42:55 +00:00
switchflag = POWER_TOGGLE ; // Toggle
2018-12-28 15:35:19 +00:00
break ;
case FOLLOW :
2020-11-03 14:42:55 +00:00
switchflag = button & 1 ; // Follow wall switch state
2018-12-28 15:35:19 +00:00
break ;
case FOLLOW_INV :
2020-11-03 14:42:55 +00:00
switchflag = ~ button & 1 ; // Follow inverted wall switch state
2018-12-28 15:35:19 +00:00
break ;
case PUSHBUTTON :
2020-03-14 12:13:33 +00:00
if ( PRESSED = = button ) {
2020-11-03 14:42:55 +00:00
switchflag = POWER_TOGGLE ; // Toggle with pushbutton to Gnd
2018-12-28 15:35:19 +00:00
}
break ;
case PUSHBUTTON_INV :
2020-03-14 12:13:33 +00:00
if ( NOT_PRESSED = = button ) {
2020-11-03 14:42:55 +00:00
switchflag = POWER_TOGGLE ; // Toggle with releasing pushbutton from Gnd
2018-12-28 15:35:19 +00:00
}
break ;
case PUSHBUTTONHOLD :
2020-03-14 12:13:33 +00:00
if ( PRESSED = = button ) {
2021-06-11 17:14:12 +01:00
Switch . hold_timer [ i ] = loops_per_second * Settings - > param [ P_HOLD_TIME ] / 10 ; // Start timer on button press
2018-12-28 15:35:19 +00:00
}
2020-03-14 12:13:33 +00:00
if ( ( NOT_PRESSED = = button ) & & ( Switch . hold_timer [ i ] ) ) {
2020-11-03 14:42:55 +00:00
Switch . hold_timer [ i ] = 0 ; // Button released and hold timer not expired : stop timer...
switchflag = POWER_TOGGLE ; // ...and Toggle
2020-03-08 12:32:20 +00:00
}
break ;
case PUSHBUTTONHOLD_INV :
2020-03-14 12:13:33 +00:00
if ( NOT_PRESSED = = button ) {
2021-06-11 17:14:12 +01:00
Switch . hold_timer [ i ] = loops_per_second * Settings - > param [ P_HOLD_TIME ] / 10 ; // Start timer on button press...
2020-03-08 12:32:20 +00:00
}
2020-03-14 12:13:33 +00:00
if ( ( PRESSED = = button ) & & ( Switch . hold_timer [ i ] ) ) {
2020-11-03 14:42:55 +00:00
Switch . hold_timer [ i ] = 0 ; // Button released and hold timer not expired : stop timer.
switchflag = POWER_TOGGLE ; // ...and Toggle
2018-12-28 15:35:19 +00:00
}
break ;
2020-01-15 12:05:00 +00:00
case TOGGLEMULTI :
case FOLLOWMULTI :
case FOLLOWMULTI_INV :
if ( Switch . hold_timer [ i ] ) {
Switch . hold_timer [ i ] = 0 ;
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_HOLD ) ; // Execute command via MQTT
mqtt_action = POWER_HOLD ;
2020-01-15 12:05:00 +00:00
} else {
2020-11-03 14:42:55 +00:00
Switch . hold_timer [ i ] = loops_per_second / 2 ; // 0.5 second multi press window
2018-12-28 15:35:19 +00:00
}
2020-01-15 12:05:00 +00:00
break ;
2020-01-25 10:22:28 +00:00
case PUSHHOLDMULTI :
2020-03-14 12:13:33 +00:00
if ( NOT_PRESSED = = button ) {
2020-08-09 07:14:09 +01:00
if ( ( Switch . hold_timer [ i ] & SM_TIMER_MASK ) ! = 0 ) {
2020-08-09 14:31:37 +01:00
Switch . hold_timer [ i ] = ( ( Switch . hold_timer [ i ] & ~ SM_TIMER_MASK ) = = SM_FIRST_PRESS ) ? SM_SECOND_PRESS : 0 ;
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_INV ) ; // Execute command via MQTT
mqtt_action = POWER_INV ;
2020-03-14 12:13:33 +00:00
}
2020-05-19 14:52:10 +01:00
} else {
2021-06-11 17:14:12 +01:00
if ( ( Switch . hold_timer [ i ] & SM_TIMER_MASK ) > loops_per_second * Settings - > param [ P_HOLD_TIME ] / 25 ) {
2021-08-26 15:36:04 +01:00
if ( ( Switch . hold_timer [ i ] & ~ SM_TIMER_MASK ) ! = SM_SECOND_PRESS ) {
2020-08-09 07:14:09 +01:00
Switch . hold_timer [ i ] = SM_FIRST_PRESS ;
2021-08-29 22:03:14 +01:00
switchflag = POWER_TOGGLE ; // Toggle with pushbutton
2020-08-04 21:53:44 +01:00
}
else {
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_100 ) ; // Execute command via MQTT
mqtt_action = POWER_100 ;
2020-08-04 21:53:44 +01:00
Switch . hold_timer [ i ] = 0 ;
}
2020-05-19 14:52:10 +01:00
} else {
2020-08-04 21:53:44 +01:00
Switch . hold_timer [ i ] = 0 ;
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_RELEASE ) ; // Execute command via MQTT
mqtt_action = POWER_RELEASE ;
2020-03-14 12:13:33 +00:00
}
2020-02-06 13:53:35 +00:00
}
2021-06-11 17:14:12 +01:00
Switch . hold_timer [ i ] = ( Switch . hold_timer [ i ] & ~ SM_TIMER_MASK ) | loops_per_second * Settings - > param [ P_HOLD_TIME ] / 10 ;
2020-01-25 10:22:28 +00:00
break ;
case PUSHHOLDMULTI_INV :
2020-03-14 12:13:33 +00:00
if ( PRESSED = = button ) {
2020-08-09 07:14:09 +01:00
if ( ( Switch . hold_timer [ i ] & SM_TIMER_MASK ) ! = 0 ) {
2020-08-09 14:31:37 +01:00
Switch . hold_timer [ i ] = ( ( Switch . hold_timer [ i ] & ~ SM_TIMER_MASK ) = = SM_FIRST_PRESS ) ? SM_SECOND_PRESS : 0 ;
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_INV ) ; // Execute command via MQTT
mqtt_action = POWER_INV ;
2020-03-14 12:13:33 +00:00
}
2020-05-19 14:52:10 +01:00
} else {
2021-06-11 17:14:12 +01:00
if ( ( Switch . hold_timer [ i ] & SM_TIMER_MASK ) > loops_per_second * Settings - > param [ P_HOLD_TIME ] / 25 ) {
2021-08-26 15:36:04 +01:00
if ( ( Switch . hold_timer [ i ] & ~ SM_TIMER_MASK ) ! = SM_SECOND_PRESS ) {
2020-08-09 07:14:09 +01:00
Switch . hold_timer [ i ] = SM_FIRST_PRESS ;
2021-08-29 22:03:14 +01:00
switchflag = POWER_TOGGLE ; // Toggle with pushbutton
2020-08-04 21:53:44 +01:00
}
else {
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_100 ) ; // Execute command via MQTT
mqtt_action = POWER_100 ;
2020-08-04 21:53:44 +01:00
Switch . hold_timer [ i ] = 0 ;
}
2020-05-19 14:52:10 +01:00
} else {
2020-08-04 21:53:44 +01:00
Switch . hold_timer [ i ] = 0 ;
2020-11-03 14:42:55 +00:00
SendKey ( KEY_SWITCH , i + 1 , POWER_RELEASE ) ; // Execute command via MQTT
mqtt_action = POWER_RELEASE ;
2020-03-14 12:13:33 +00:00
}
2020-01-25 10:22:28 +00:00
}
2021-06-11 17:14:12 +01:00
Switch . hold_timer [ i ] = ( Switch . hold_timer [ i ] & ~ SM_TIMER_MASK ) | loops_per_second * Settings - > param [ P_HOLD_TIME ] / 10 ;
2020-01-25 10:22:28 +00:00
break ;
2020-03-14 10:41:57 +00:00
case PUSHON :
2020-03-14 12:13:33 +00:00
if ( PRESSED = = button ) {
2020-11-03 14:42:55 +00:00
switchflag = POWER_ON ; // Power ON with pushbutton to Gnd
2020-03-14 12:13:33 +00:00
}
break ;
case PUSHON_INV :
if ( NOT_PRESSED = = button ) {
2020-11-03 14:42:55 +00:00
switchflag = POWER_ON ; // Power ON with releasing pushbutton from Gnd
2020-03-14 12:13:33 +00:00
}
2020-03-14 10:41:57 +00:00
break ;
2020-10-18 11:17:31 +01:00
case PUSH_IGNORE :
2020-11-14 18:31:38 +00:00
Switch . last_state [ i ] = button ; // Update switch state before publishing
2020-10-18 11:17:31 +01:00
MqttPublishSensor ( ) ;
break ;
2018-12-28 15:35:19 +00:00
}
2019-08-17 15:19:58 +01:00
Switch . last_state [ i ] = button ;
2018-12-28 15:35:19 +00:00
}
2020-01-15 12:05:00 +00:00
if ( switchflag < = POWER_TOGGLE ) {
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag5 . mqtt_switches ) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes
2020-11-03 14:42:55 +00:00
if ( ! SendKey ( KEY_SWITCH , i + 1 , switchflag ) ) { // Execute command via MQTT
2020-11-02 23:44:07 +00:00
ExecuteCommandPower ( i + 1 , switchflag , SRC_SWITCH ) ; // Execute command internally (if i < TasmotaGlobal.devices_present)
}
2020-11-03 14:42:55 +00:00
} else { mqtt_action = switchflag ; }
2020-11-02 23:44:07 +00:00
}
2021-06-11 17:14:12 +01:00
if ( ( mqtt_action ! = POWER_NONE ) & & Settings - > flag5 . mqtt_switches ) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes
if ( ! Settings - > flag . hass_discovery ) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
2020-11-03 14:42:55 +00:00
char mqtt_state_str [ 16 ] ;
char * mqtt_state = mqtt_state_str ;
if ( mqtt_action < = 3 ) {
if ( mqtt_action ! = 3 ) { SendKey ( KEY_SWITCH , i + 1 , mqtt_action ) ; }
mqtt_state = SettingsText ( SET_STATE_TXT1 + mqtt_action ) ;
} else {
GetTextIndexed ( mqtt_state_str , sizeof ( mqtt_state_str ) , mqtt_action , kSwitchPressStates ) ;
}
2020-11-03 15:24:49 +00:00
Response_P ( S_JSON_SVALUE_ACTION_SVALUE , GetSwitchText ( i ) . c_str ( ) , mqtt_state ) ;
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_SWITCH " %d " ) , i + 1 ) ;
2020-11-03 15:05:57 +00:00
MqttPublishPrefixTopicRulesProcess_P ( RESULT_OR_STAT , scommand ) ;
2020-11-03 14:42:55 +00:00
}
mqtt_action = POWER_NONE ;
2020-01-15 12:05:00 +00:00
}
2018-12-28 15:35:19 +00:00
}
}
}
2020-11-03 13:34:02 +00:00
void SwitchLoop ( void ) {
2019-08-17 15:19:58 +01:00
if ( Switch . present ) {
if ( TimeReached ( Switch . debounce ) ) {
2021-06-11 17:14:12 +01:00
SetNextTimeInterval ( Switch . debounce , Settings - > switch_debounce ) ;
2018-12-28 15:35:19 +00:00
SwitchHandler ( 0 ) ;
}
}
}
2020-03-14 12:13:33 +00:00
# endif // SWITCH_V3