Browse Source

btn: generate pressed & released events from switch changes (#2379)

- Add ::Released button event to be used specifically with switches, opposite of ::Pressed
- Always use default state for switches instead of ignoring it and using current pin reading as value. This allows us to boot with the switch held in the opposite state and trigger the correct event immediately
(meaning, switches now depend on the BUTTON_DEFAULT_HIGH presence to detect the default position)
- BREAKING: Fixup hardware.h. Any custom board needs manual changes.
- BREAKING: Rework MQTT button messages to send text from debug messages instead of numeric code
mcspr-patch-1
Max Prokhorov 4 years ago
committed by GitHub
parent
commit
7a64a4a6bf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 108 additions and 83 deletions
  1. +4
    -4
      code/espurna/DebounceEvent.cpp
  2. +21
    -53
      code/espurna/button.cpp
  3. +9
    -8
      code/espurna/button.h
  4. +13
    -0
      code/espurna/button_config.h
  5. +25
    -0
      code/espurna/config/defaults.h
  6. +34
    -15
      code/espurna/config/hardware.h
  7. +2
    -2
      code/espurna/config/types.h
  8. +0
    -1
      code/espurna/libs/DebounceEvent.h

+ 4
- 4
code/espurna/DebounceEvent.cpp View File

@ -42,7 +42,7 @@ EventEmitter::EventEmitter(types::Pin pin, types::EventHandler callback, const t
_default_value(config.default_value == types::PinValue::High),
_delay(debounce_delay),
_repeat(repeat),
_value(false),
_value(_default_value),
_ready(false),
_reset_count(true),
_event_start(0),
@ -70,8 +70,6 @@ EventEmitter::EventEmitter(types::Pin pin, types::EventHandler callback, const t
} else {
_pin->pinMode(INPUT);
}
_value = _is_switch ? (_pin->digitalRead() == (HIGH)) : _default_value;
}
EventEmitter::EventEmitter(types::Pin pin, const types::Config& config, unsigned long delay, unsigned long repeat) :
@ -119,7 +117,9 @@ types::Event EventEmitter::loop() {
_value = !_value;
if (_is_switch) {
event = types::EventChanged;
event = isPressed()
? types::EventPressed
: types::EventReleased;
} else {
if (_value == _default_value) {
_event_length = millis() - _event_start;


+ 21
- 53
code/espurna/button.cpp View File

@ -141,6 +141,7 @@ constexpr const debounce_event::types::Config _buttonDecodeConfigBitmask(const u
constexpr const button_action_t _buttonDecodeEventAction(const button_actions_t& actions, button_event_t event) {
return (
(event == button_event_t::Pressed) ? actions.pressed :
(event == button_event_t::Released) ? actions.released :
(event == button_event_t::Click) ? actions.click :
(event == button_event_t::DoubleClick) ? actions.dblclick :
(event == button_event_t::LongClick) ? actions.lngclick :
@ -151,6 +152,7 @@ constexpr const button_action_t _buttonDecodeEventAction(const button_actions_t&
constexpr const button_event_t _buttonMapReleased(uint8_t count, unsigned long length, unsigned long lngclick_delay, unsigned long lnglngclick_delay) {
return (
(0 == count) ? button_event_t::Released :
(1 == count) ? (
(length > lnglngclick_delay) ? button_event_t::LongLongClick :
(length > lngclick_delay) ? button_event_t::LongClick : button_event_t::Click
@ -164,6 +166,7 @@ constexpr const button_event_t _buttonMapReleased(uint8_t count, unsigned long l
button_actions_t _buttonConstructActions(unsigned char index) {
return {
_buttonPress(index),
_buttonRelease(index),
_buttonClick(index),
_buttonDoubleClick(index),
_buttonLongClick(index),
@ -220,20 +223,10 @@ bool button_t::state() {
}
button_event_t button_t::loop() {
if (!event_emitter) {
return button_event_t::None;
}
auto event = event_emitter->loop();
if (event == debounce_event::types::EventNone) {
return button_event_t::None;
}
switch (event) {
if (event_emitter) {
switch (event_emitter->loop()) {
case debounce_event::types::EventPressed:
return button_event_t::Pressed;
case debounce_event::types::EventChanged:
return button_event_t::Click;
case debounce_event::types::EventReleased: {
return _buttonMapReleased(
event_emitter->getEventCount(),
@ -243,8 +236,8 @@ button_event_t button_t::loop() {
);
}
case debounce_event::types::EventNone:
default:
break;
}
}
return button_event_t::None;
@ -267,13 +260,6 @@ std::bitset<ButtonsMax> _buttons_mqtt_retain(
(1 == BUTTON_MQTT_RETAIN) ? 0xFFFFFFFFUL : 0UL
);
void buttonMQTT(unsigned char id, button_event_t event) {
char payload[4] = {0};
itoa(_buttonEventNumber(event), payload, 10);
// mqttSend(topic, id, payload, force, retain)
mqttSend(MQTT_TOPIC_BUTTON, id, payload, false, _buttons_mqtt_retain[id]);
}
#endif
#if WEB_SUPPORT
@ -391,60 +377,40 @@ button_action_t buttonAction(unsigned char id, const button_event_t event) {
return _buttonDecodeEventAction(_buttons[id].actions, event);
}
// Approach based on https://github.com/esp8266/Arduino/pull/6950
// "PROGMEM footprint cleanup for responseCodeToString (#6950)"
// Note that we don't directly return F(...), but use a temporary to assign it conditionally
// (ref. https://github.com/esp8266/Arduino/pull/6950 "PROGMEM footprint cleanup for responseCodeToString")
// In this particular case, saves 76 bytes (120 vs 44)
#if 1
String _buttonEventString(button_event_t event) {
const __FlashStringHelper* ptr = nullptr;
switch (event) {
case button_event_t::Pressed:
ptr = F("Pressed");
ptr = F("pressed");
break;
case button_event_t::Released:
ptr = F("released");
break;
case button_event_t::Click:
ptr = F("Click");
ptr = F("click");
break;
case button_event_t::DoubleClick:
ptr = F("Double-click");
ptr = F("double-click");
break;
case button_event_t::LongClick:
ptr = F("Long-click");
ptr = F("long-click");
break;
case button_event_t::LongLongClick:
ptr = F("Looong-click");
ptr = F("looong-click");
break;
case button_event_t::TripleClick:
ptr = F("Triple-click");
ptr = F("triple-click");
break;
case button_event_t::None:
default:
ptr = F("None");
ptr = F("none");
break;
}
return String(ptr);
}
#else
String _buttonEventString(button_event_t event) {
switch (event) {
case button_event_t::Pressed:
return F("Pressed");
case button_event_t::Click:
return F("Click");
case button_event_t::DoubleClick:
return F("Double-click");
case button_event_t::LongClick:
return F("Long-click");
case button_event_t::LongLongClick:
return F("Looong-click");
case button_event_t::TripleClick:
return F("Triple-click");
case button_event_t::None:
default:
return F("None");
}
}
#endif
void buttonEvent(unsigned char id, button_event_t event) {
@ -462,7 +428,7 @@ void buttonEvent(unsigned char id, button_event_t event) {
#if MQTT_SUPPORT
if (action || _buttons_mqtt_send_all[id]) {
buttonMQTT(id, event);
mqttSend(MQTT_TOPIC_BUTTON, id, _buttonEventString(event).c_str(), false, _buttons_mqtt_retain[id]);
}
#endif
@ -828,6 +794,7 @@ void buttonSetup() {
for (unsigned char index = 0; index < buttons; ++index) {
const button_actions_t actions {
BUTTON_ACTION_NONE,
BUTTON_ACTION_NONE,
// The only generated event is ::Click
getSetting({"btnClick", index}, _buttonClick(index)),
@ -872,6 +839,7 @@ void buttonSetup() {
const button_actions_t actions {
getSetting({"btnPress", index}, _buttonPress(index)),
getSetting({"btnRlse", index}, _buttonRelease(index)),
getSetting({"btnClick", index}, _buttonClick(index)),
getSetting({"btnDclk", index}, _buttonDoubleClick(index)),
getSetting({"btnLclk", index}, _buttonLongClick(index)),


+ 9
- 8
code/espurna/button.h View File

@ -23,17 +23,19 @@ constexpr size_t ButtonsMax = 32;
using button_action_t = uint8_t;
enum class button_event_t {
None = 0,
Pressed = 1,
Click = 2,
DoubleClick = 3,
LongClick = 4,
LongLongClick = 5,
TripleClick = 6
None,
Pressed,
Released,
Click,
DoubleClick,
LongClick,
LongLongClick,
TripleClick
};
struct button_actions_t {
button_action_t pressed;
button_action_t released;
button_action_t click;
button_action_t dblclick;
button_action_t lngclick;
@ -74,7 +76,6 @@ BrokerDeclare(ButtonBroker, void(unsigned char id, button_event_t event));
bool buttonState(unsigned char id);
button_action_t buttonAction(unsigned char id, const button_event_t event);
void buttonMQTT(unsigned char id, button_event_t event);
void buttonEvent(unsigned char id, button_event_t event);
unsigned char buttonCount();


+ 13
- 0
code/espurna/button_config.h View File

@ -46,6 +46,19 @@ constexpr const unsigned char _buttonConfigBitmask(unsigned char index) {
);
}
constexpr const unsigned char _buttonRelease(unsigned char index) {
return (
(index == 0) ? BUTTON1_RELEASE :
(index == 1) ? BUTTON2_RELEASE :
(index == 2) ? BUTTON3_RELEASE :
(index == 3) ? BUTTON4_RELEASE :
(index == 4) ? BUTTON5_RELEASE :
(index == 5) ? BUTTON6_RELEASE :
(index == 6) ? BUTTON7_RELEASE :
(index == 7) ? BUTTON8_RELEASE : BUTTON_ACTION_NONE
);
}
constexpr const unsigned char _buttonPress(unsigned char index) {
return (
(index == 0) ? BUTTON1_PRESS :


+ 25
- 0
code/espurna/config/defaults.h View File

@ -83,6 +83,31 @@
#define BUTTON8_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON1_RELEASE
#define BUTTON1_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON2_RELEASE
#define BUTTON2_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON3_RELEASE
#define BUTTON3_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON4_RELEASE
#define BUTTON4_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON5_RELEASE
#define BUTTON5_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON6_RELEASE
#define BUTTON6_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON7_RELEASE
#define BUTTON7_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON8_RELEASE
#define BUTTON8_RELEASE BUTTON_ACTION_NONE
#endif
#ifndef BUTTON1_CLICK
#define BUTTON1_CLICK BUTTON_ACTION_TOGGLE
#endif


+ 34
- 15
code/espurna/config/hardware.h View File

@ -1682,11 +1682,16 @@
// Buttons
#define BUTTON1_PIN 5
#define BUTTON2_PIN 4
#define BUTTON1_RELAY 1
#define BUTTON2_RELAY 2
#define BUTTON1_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH | BUTTON_SET_PULLUP
#define BUTTON1_PRESS BUTTON_ACTION_ON
#define BUTTON1_RELEASE BUTTON_ACTION_OFF
#define BUTTON2_PIN 4
#define BUTTON2_RELAY 2
#define BUTTON2_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH | BUTTON_SET_PULLUP
#define BUTTON2_PRESS BUTTON_ACTION_ON
#define BUTTON2_RELEASE BUTTON_ACTION_OFF
// Relays
#define RELAY1_PIN 14
@ -2560,11 +2565,8 @@
#define BUTTON1_CONFIG BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1
#define BUTTON1_PRESS BUTTON_ACTION_NONE
#define BUTTON1_CLICK BUTTON_ACTION_TOGGLE
#define BUTTON1_DBLCLICK BUTTON_ACTION_NONE
#define BUTTON1_LNGCLICK BUTTON_ACTION_NONE
#define BUTTON1_LNGLNGCLICK BUTTON_ACTION_NONE
#define BUTTON1_PRESS BUTTON_ACTION_ON
#define BUTTON1_RELEASE BUTTON_ACTION_OFF
// Relays
#define RELAY1_PIN 5 // D1
@ -2842,17 +2844,15 @@
#define BUTTON1_RELAY 1
#define BUTTON1_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH //Hardware Pullup
#define BUTTON1_PRESS BUTTON_ACTION_NONE
#define BUTTON1_CLICK BUTTON_ACTION_TOGGLE
#define BUTTON1_DBLCLICK BUTTON_ACTION_NONE
#define BUTTON1_LNGCLICK BUTTON_ACTION_NONE
#define BUTTON1_LNGLNGCLICK BUTTON_ACTION_NONE
#define BUTTON1_PRESS BUTTON_ACTION_ON
#define BUTTON1_RELEASE BUTTON_ACTION_OFF
#define BUTTON2_PIN 13
#define BUTTON2_RELAY 2
#define BUTTON2_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH //Hardware Pullup
#define BUTTON2_CLICK BUTTON_ACTION_TOGGLE
#define BUTTON2_PRESS BUTTON_ACTION_ON
#define BUTTON2_RELEASE BUTTON_ACTION_OFF
// Relays
#define RELAY1_PIN 4
@ -3664,6 +3664,9 @@
#define BUTTON1_CONFIG BUTTON_SWITCH
#define BUTTON1_RELAY 1
#define BUTTON1_PRESS BUTTON_ACTION_ON
#define BUTTON1_RELEASE BUTTON_ACTION_OFF
// Relays
#define RELAY1_PIN 4
#define RELAY1_TYPE RELAY_TYPE_NORMAL
@ -3676,12 +3679,19 @@
// Buttons
#define BUTTON1_PIN 12
#define BUTTON2_PIN 14
#define BUTTON1_RELAY 1
#define BUTTON1_CONFIG BUTTON_SWITCH
#define BUTTON1_PRESS BUTTON_ACTION_ON
#define BUTTON1_RELEASE BUTTON_ACTION_OFF
#define BUTTON2_PIN 14
#define BUTTON2_CONFIG BUTTON_SWITCH
#define BUTTON1_RELAY 1
#define BUTTON2_RELAY 2
#define BUTTON2_PRESS BUTTON_ACTION_ON
#define BUTTON2_RELEASE BUTTON_ACTION_OFF
// Relays
#define RELAY1_PIN 4
#define RELAY1_TYPE RELAY_TYPE_NORMAL
@ -3698,6 +3708,9 @@
#define BUTTON1_CONFIG BUTTON_SWITCH
#define BUTTON1_RELAY 1
#define BUTTON1_PRESS BUTTON_ACTION_ON
#define BUTTON1_RELEASE BUTTON_ACTION_OFF
#define BUTTON2_PIN 2
#define BUTTON2_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON2_LNGCLICK BUTTON_ACTION_RESET
@ -3741,10 +3754,16 @@
#define BUTTON1_CONFIG BUTTON_SWITCH
#define BUTTON1_RELAY 1
#define BUTTON1_PRESS BUTTON_ACTION_ON
#define BUTTON1_RELEASE BUTTON_ACTION_OFF
#define BUTTON2_PIN 5
#define BUTTON2_CONFIG BUTTON_SWITCH
#define BUTTON2_RELAY 2
#define BUTTON2_PRESS BUTTON_ACTION_ON
#define BUTTON2_RELEASE BUTTON_ACTION_OFF
#define BUTTON3_PIN 2
#define BUTTON3_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON3_LNGCLICK BUTTON_ACTION_RESET


+ 2
- 2
code/espurna/config/types.h View File

@ -19,7 +19,7 @@
// BUTTONS
//------------------------------------------------------------------------------
// button actions, limited to 4-bit number (0b1111 / 0xf / 15)
// button actions, limited to 8-bit number (0b11111111 / 0xff / 255)
#define BUTTON_ACTION_NONE 0u
#define BUTTON_ACTION_TOGGLE 1u
#define BUTTON_ACTION_ON 2u
@ -33,7 +33,7 @@
#define BUTTON_ACTION_DIM_UP 10u
#define BUTTON_ACTION_DIM_DOWN 11u
#define BUTTON_ACTION_DISPLAY_ON 12u
#define BUTTON_ACTION_MAX 15u
#define BUTTON_ACTION_MAX 255u
// Deprecated: legacy mapping, changed to action from above
#define BUTTON_MODE_NONE BUTTON_ACTION_NONE


+ 0
- 1
code/espurna/libs/DebounceEvent.h View File

@ -69,7 +69,6 @@ namespace types {
enum Event {
EventNone,
EventChanged,
EventPressed,
EventReleased
};


Loading…
Cancel
Save