6.1.1.12 - Add debounce time

6.1.1.12 20180827
 * Add commands ButtonDebounce 40..1000 and SwitchDebounce 40..1000 to have more control over debounce timing. Default is 50mS (#3594)
This commit is contained in:
Theo Arends 2018-08-27 12:01:20 +02:00
parent 1b8adc2eef
commit d69e88b50b
7 changed files with 86 additions and 53 deletions

View File

@ -1,4 +1,7 @@
/* 6.1.1.11 20180826
/* 6.1.1.12 20180827
* Add commands ButtonDebounce 40..1000 and SwitchDebounce 40..1000 to have more control over debounce timing. Default is 50mS (#3594)
*
* 6.1.1.11 20180826
* Change scheduler phase 1/3 - Fixed when sleep is enabled: Uptime, Delay, PulseTime and TelePeriod (#3581)
* Change scheduler phase 2/3 - Fixed when sleep is enabled: Blinktime (#3581)
* Change scheduler phase 3/3 - Some sensor update timings: AdcEvery 200 -> 250, Senseair 300 -> 250, SDM120 300 -> 250, SDM630 300 -> 250

View File

@ -192,6 +192,8 @@
#define D_CMND_COUNTER "Counter"
#define D_CMND_COUNTERTYPE "CounterType"
#define D_CMND_COUNTERDEBOUNCE "CounterDebounce"
#define D_CMND_BUTTONDEBOUNCE "ButtonDebounce"
#define D_CMND_SWITCHDEBOUNCE "SwitchDebounce"
#define D_CMND_SLEEP "Sleep"
#define D_CMND_UPLOAD "Upload"
#define D_CMND_UPGRADE "Upgrade"

View File

@ -297,9 +297,7 @@ struct SYSCFG {
char ntp_server[3][33]; // 4CE
byte ina219_mode; // 531
uint16_t pulse_timer[MAX_PULSETIMERS]; // 532
byte free542[2]; // 542
uint16_t button_debounce; // 542
uint32_t ip_address[4]; // 544
unsigned long energy_kWhtotal; // 554
char mqtt_fulltopic[100]; // 558
@ -309,8 +307,9 @@ struct SYSCFG {
uint16_t pulse_counter_debounce; // 5D2
uint8_t rf_code[17][9]; // 5D4
byte free_66d[3]; // 66D
byte free_66d[1]; // 66D
uint16_t switch_debounce; // 66E
Timer timer[MAX_TIMERS]; // 670
int latitude; // 6B0
int longitude; // 6B4
@ -321,7 +320,9 @@ struct SYSCFG {
byte knx_CB_param[MAX_KNX_CB]; // 6EC Type of Output (set relay, toggle relay, reply sensor value)
Mcp230xxCfg mcp230xx_config[16]; // 6F6
uint8_t mcp230xx_int_prio; // 716
byte free_717; // 717
byte free_717[1]; // 717
uint16_t mcp230xx_int_timer; // 718
byte free_71A[180]; // 71A

View File

@ -588,6 +588,9 @@ void SettingsDefaultSet2()
Settings.latitude = (int)((double)LATITUDE * 1000000);
Settings.longitude = (int)((double)LONGITUDE * 1000000);
SettingsDefaultSet_5_13_1c(); // Time STD/DST settings
Settings.button_debounce = KEY_DEBOUNCE_TIME;
Settings.switch_debounce = SWITCH_DEBOUNCE_TIME;
}
/********************************************************************************************/
@ -787,6 +790,10 @@ void SettingsDelta()
if (Settings.version < 0x06010103) {
Settings.flag3.timers_enable = 1;
}
if (Settings.version < 0x0601010C) {
Settings.button_debounce = KEY_DEBOUNCE_TIME;
Settings.switch_debounce = SWITCH_DEBOUNCE_TIME;
}
Settings.version = VERSION;
SettingsSave(1);

View File

@ -79,7 +79,7 @@ enum TasmotaCommands {
CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SENSOR, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION,
CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_MODULE, CMND_MODULES,
CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE,
CMND_COUNTERDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG,
CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG,
CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME,
CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE,
CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE,
@ -89,7 +89,7 @@ const char kTasmotaCommands[] PROGMEM =
D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|"
D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_MODULE "|" D_CMND_MODULES "|"
D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|"
D_CMND_COUNTERDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|"
D_CMND_COUNTERDEBOUNCE "|" D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|"
D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|"
D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|"
D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|"
@ -102,20 +102,28 @@ unsigned long feature_drv1; // Compiled driver feature map
unsigned long feature_drv2; // Compiled driver feature map
unsigned long feature_sns1; // Compiled sensor feature map
unsigned long feature_sns2; // Compiled sensor feature map
unsigned long serial_polling_window = 0; // Serial polling window
unsigned long state_second = 0; // State second timer
unsigned long state_50msecond = 0; // State 50msecond timer
unsigned long state_100msecond = 0; // State 100msecond timer
unsigned long state_250msecond = 0; // State 250msecond timer
unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer
unsigned long blink_timer = 0; // Power cycle timer
unsigned long backlog_delay = 0; // Command backlog delay
unsigned long button_debounce = 0; // Button debounce timer
unsigned long switch_debounce = 0; // Switch debounce timer
power_t power = 0; // Current copy of Settings.power
int baudrate = APP_BAUDRATE; // Serial interface baud rate
SerialConfig serial_config = SERIAL_8N1; // Serial interface configuration 8 data bits, No parity, 1 stop bit
byte serial_in_byte; // Received byte
uint8_t serial_local = 0; // Handle serial locally;
unsigned long serial_polling_window = 0; // Serial polling window
int serial_in_byte_counter = 0; // Index in receive buffer
byte dual_hex_code = 0; // Sonoff dual input flag
uint16_t dual_button_code = 0; // Sonoff dual received code
int16_t save_data_counter; // Counter and flag for config save to Flash
uint8_t fallback_topic_flag = 0; // Use Topic or FallbackTopic
unsigned long state_second = 0; // State second timer
unsigned long state_50msecond = 0; // State 50msecond timer
unsigned long state_100msecond = 0; // State 100msecond timer
unsigned long state_250msecond = 0; // State 250msecond timer
uint8_t state_250mS = 0; // State 250msecond per second flag
int ota_state_flag = 0; // OTA state flag
int ota_result = 0; // OTA result
@ -130,8 +138,6 @@ byte web_log_index = 1; // Index in Web log buffer (should n
byte reset_web_log_flag = 0; // Reset web console log
byte devices_present = 0; // Max number of devices supported
int status_update_timer = 0; // Refresh initial status
unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer
unsigned long blink_timer = 0; // Power cycle timer
uint16_t blink_counter = 0; // Number of blink cycles
power_t blink_power; // Blink power state
power_t blink_mask = 0; // Blink relay active mask
@ -142,7 +148,6 @@ uint8_t latching_relay_pulse = 0; // Latching relay pulse timer
uint8_t backlog_index = 0; // Command backlog index
uint8_t backlog_pointer = 0; // Command backlog pointer
uint8_t backlog_mutex = 0; // Command backlog pending
unsigned long backlog_delay = 0; // Command backlog delay
uint8_t interlock_mutex = 0; // Interlock power command pending
#ifdef USE_MQTT_TLS
@ -153,7 +158,6 @@ uint8_t interlock_mutex = 0; // Interlock power command pending
WiFiUDP PortUdp; // UDP Syslog and Alexa
power_t power = 0; // Current copy of Settings.power
byte syslog_level; // Current copy of Settings.syslog_level
uint16_t syslog_timer = 0; // Timer to re-enable syslog_level
byte seriallog_level; // Current copy of Settings.seriallog_level
@ -947,6 +951,18 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.pulse_counter_debounce);
}
else if (CMND_BUTTONDEBOUNCE == command_code) {
if ((payload > 39) && (payload < 1001)) {
Settings.button_debounce = payload16;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.button_debounce);
}
else if (CMND_SWITCHDEBOUNCE == command_code) {
if ((payload > 39) && (payload < 1001)) {
Settings.switch_debounce = payload16;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.switch_debounce);
}
else if (CMND_BAUDRATE == command_code) {
if (payload32 > 0) {
payload32 /= 1200; // Make it a valid baudrate
@ -1631,7 +1647,8 @@ void ButtonHandler()
{
uint8_t button = NOT_PRESSED;
uint8_t button_present = 0;
uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command
uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command
uint16_t loops_per_second = 1000 / Settings.button_debounce;
char scmnd[20];
uint8_t maxdev = (devices_present > MAX_KEYS) ? MAX_KEYS : devices_present;
@ -1645,8 +1662,8 @@ void ButtonHandler()
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), dual_button_code);
AddLog(LOG_LEVEL_DEBUG);
button = PRESSED;
if (0xF500 == dual_button_code) { // Button hold
holdbutton[button_index] = (Settings.param[P_HOLD_TIME] * (STATES / 10)) -1;
if (0xF500 == dual_button_code) { // Button hold
holdbutton[button_index] = (loops_per_second * Settings.param[P_HOLD_TIME] / 10) -1;
hold_time_extent = 1;
}
dual_button_code = 0;
@ -1660,28 +1677,28 @@ void ButtonHandler()
if (button_present) {
if (SONOFF_4CHPRO == Settings.module) {
if (holdbutton[button_index]) holdbutton[button_index]--;
if (holdbutton[button_index]) { holdbutton[button_index]--; }
boolean button_pressed = false;
if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1);
AddLog(LOG_LEVEL_DEBUG);
holdbutton[button_index] = STATES;
holdbutton[button_index] = loops_per_second;
button_pressed = true;
}
if ((NOT_PRESSED == button) && (PRESSED == lastbutton[button_index])) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1);
AddLog(LOG_LEVEL_DEBUG);
if (!holdbutton[button_index]) button_pressed = true; // Do not allow within 1 second
if (!holdbutton[button_index]) { button_pressed = true; } // Do not allow within 1 second
}
if (button_pressed) {
if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
if (!SendKey(0, 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 {
if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) {
if (Settings.flag.button_single) { // Allow only single button press for immediate action
if (Settings.flag.button_single) { // Allow only single button press for immediate action
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1);
AddLog(LOG_LEVEL_DEBUG);
if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
@ -1691,7 +1708,7 @@ void ButtonHandler()
multipress[button_index] = (multiwindow[button_index]) ? multipress[button_index] +1 : 1;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, multipress[button_index]);
AddLog(LOG_LEVEL_DEBUG);
multiwindow[button_index] = STATES /2; // 0.5 second multi press window
multiwindow[button_index] = loops_per_second / 2; // 0.5 second multi press window
}
blinks = 201;
}
@ -1700,20 +1717,20 @@ void ButtonHandler()
holdbutton[button_index] = 0;
} else {
holdbutton[button_index]++;
if (Settings.flag.button_single) { // Allow only single button press for immediate action
if (holdbutton[button_index] == Settings.param[P_HOLD_TIME] * (STATES / 10) * hold_time_extent) { // Button held for factor times longer
if (Settings.flag.button_single) { // Allow only single button press for immediate action
if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer
// Settings.flag.button_single = 0;
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only
ExecuteCommand(scmnd, SRC_BUTTON);
}
} else {
if (Settings.flag.button_restrict) { // Button restriction
if (holdbutton[button_index] == Settings.param[P_HOLD_TIME] * (STATES / 10)) { // Button hold
if (Settings.flag.button_restrict) { // Button restriction
if (holdbutton[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // Button hold
multipress[button_index] = 0;
SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set
SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set
}
} else {
if (holdbutton[button_index] == (Settings.param[P_HOLD_TIME] * (STATES / 10)) * hold_time_extent) { // Button held for factor times longer
if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer
multipress[button_index] = 0;
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1"));
ExecuteCommand(scmnd, SRC_BUTTON);
@ -1722,13 +1739,13 @@ void ButtonHandler()
}
}
if (!Settings.flag.button_single) { // Allow multi-press
if (!Settings.flag.button_single) { // Allow multi-press
if (multiwindow[button_index]) {
multiwindow[button_index]--;
} else {
if (!restart_flag && !holdbutton[button_index] && (multipress[button_index] > 0) && (multipress[button_index] < MAX_BUTTON_COMMANDS +3)) {
boolean single_press = false;
if (multipress[button_index] < 3) { // Single or Double press
if (multipress[button_index] < 3) { // Single or Double press
if ((SONOFF_DUAL_R2 == Settings.module) || (SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
single_press = true;
} else {
@ -1739,13 +1756,13 @@ void ButtonHandler()
if (single_press && SendKey(0, button_index + multipress[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
// Success
} else {
if (multipress[button_index] < 3) { // Single or Double press
if (WifiState()) { // WPSconfig, Smartconfig or Wifimanager active
if (multipress[button_index] < 3) { // Single or Double press
if (WifiState()) { // WPSconfig, Smartconfig or Wifimanager active
restart_flag = 1;
} else {
ExecuteCommandPower(button_index + multipress[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
}
} else { // 3 - 7 press
} else { // 3 - 7 press
if (!Settings.flag.button_restrict) {
snprintf_P(scmnd, sizeof(scmnd), kCommands[multipress[button_index] -3]);
ExecuteCommand(scmnd, SRC_BUTTON);
@ -1770,6 +1787,7 @@ void SwitchHandler(byte mode)
{
uint8_t button = NOT_PRESSED;
uint8_t switchflag;
uint16_t loops_per_second = 1000 / Settings.switch_debounce;
for (byte i = 0; i < MAX_SWITCHES; i++) {
if ((pin[GPIO_SWT1 +i] < 99) || (mode)) {
@ -1777,7 +1795,7 @@ void SwitchHandler(byte mode)
if (holdwallswitch[i]) {
holdwallswitch[i]--;
if (0 == holdwallswitch[i]) {
SendKey(1, i +1, 3); // Execute command via MQTT
SendKey(1, i +1, 3); // Execute command via MQTT
}
}
@ -1816,7 +1834,7 @@ void SwitchHandler(byte mode)
break;
case PUSHBUTTONHOLD:
if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) {
holdwallswitch[i] = Settings.param[P_HOLD_TIME] * (STATES / 10);
holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10;
}
if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) {
holdwallswitch[i] = 0;
@ -1825,18 +1843,18 @@ void SwitchHandler(byte mode)
break;
case PUSHBUTTONHOLD_INV:
if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) {
holdwallswitch[i] = Settings.param[P_HOLD_TIME] * (STATES / 10);
holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10;
}
if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) {
holdwallswitch[i] = 0;
switchflag = 2; // Toggle with pushbutton to Gnd
switchflag = 2; // Toggle with pushbutton to Gnd
}
break;
}
if (switchflag < 3) {
if (!SendKey(1, i +1, switchflag)) { // Execute command via MQTT
ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present)
ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present)
}
}
@ -1849,15 +1867,6 @@ void SwitchHandler(byte mode)
/*********************************************************************************************\
* State loops
\*********************************************************************************************/
void Every50mSeconds()
{
// As the max amount of sleep = 250 mSec this loop will shift in time...
ButtonHandler();
SwitchHandler(0);
}
/*-------------------------------------------------------------------------------------------*\
* Every 0.1 second
\*-------------------------------------------------------------------------------------------*/
@ -2607,9 +2616,18 @@ void loop()
OsWatchLoop();
if (TimeReached(button_debounce)) {
SetNextTimeInterval(button_debounce, Settings.button_debounce);
ButtonHandler();
}
if (TimeReached(switch_debounce)) {
SetNextTimeInterval(switch_debounce, Settings.switch_debounce);
SwitchHandler(0);
}
if (TimeReached(state_50msecond)) {
SetNextTimeInterval(state_50msecond, 50);
Every50mSeconds();
XdrvCall(FUNC_EVERY_50_MSECOND);
XsnsCall(FUNC_EVERY_50_MSECOND);
}

View File

@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
#define VERSION 0x0601010B
#define VERSION 0x0601010C
#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"

View File

@ -167,7 +167,9 @@
#define APP_BLINKCOUNT 10 // [BlinkCount] Number of blinks (0 = 32000)
#define APP_SLEEP 0 // [Sleep] Sleep time to lower energy consumption (0 = Off, 1 - 250 mSec)
#define KEY_DEBOUNCE_TIME 50 // [ButtonDebounce] Number of mSeconds button press debounce time
#define KEY_HOLD_TIME 40 // [SetOption32] Number of 0.1 seconds to hold Button or external Pushbutton before sending HOLD message
#define SWITCH_DEBOUNCE_TIME 50 // [SwitchDebounce] Number of mSeconds switch press debounce time
#define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE (the wall switch state)
#define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with (max is 512)