Browse Source

button: custom action + ifan fixes

pull/2429/head
Maxim Prokhorov 3 years ago
parent
commit
ef194c9c24
6 changed files with 210 additions and 133 deletions
  1. +130
    -78
      code/espurna/button.cpp
  2. +38
    -15
      code/espurna/button.h
  3. +7
    -7
      code/espurna/button_config.h
  4. +8
    -0
      code/espurna/config/hardware.h
  5. +16
    -15
      code/espurna/config/types.h
  6. +11
    -18
      code/espurna/ifan.cpp

+ 130
- 78
code/espurna/button.cpp View File

@ -136,7 +136,34 @@ ButtonProvider convert(const String& value) {
return ButtonProvider::None;
}
} // namespace settings::internal
template<>
ButtonAction convert(const String& value) {
auto num = strtoul(value.c_str(), nullptr, 10);
if (num < ButtonsActionMax) {
auto action = static_cast<ButtonAction>(num);
switch (action) {
case ButtonAction::None:
case ButtonAction::Toggle:
case ButtonAction::On:
case ButtonAction::Off:
case ButtonAction::AccessPoint:
case ButtonAction::Reset:
case ButtonAction::Pulse:
case ButtonAction::FactoryReset:
case ButtonAction::Wps:
case ButtonAction::SmartConfig:
case ButtonAction::BrightnessIncrease:
case ButtonAction::BrightnessDecrease:
case ButtonAction::DisplayOn:
case ButtonAction::Custom:
return action;
}
}
return ButtonAction::None;
}
} // namespace internal
} // namespace settings
// -----------------------------------------------------------------------------
@ -156,7 +183,7 @@ constexpr debounce_event::types::Config _buttonDecodeConfigBitmask(int bitmask)
};
}
constexpr button_action_t _buttonDecodeEventAction(const button_actions_t& actions, button_event_t event) {
constexpr ButtonAction _buttonDecodeEventAction(const ButtonActions& actions, button_event_t event) {
return (
(event == button_event_t::Pressed) ? actions.pressed :
(event == button_event_t::Released) ? actions.released :
@ -164,7 +191,7 @@ constexpr button_action_t _buttonDecodeEventAction(const button_actions_t& actio
(event == button_event_t::DoubleClick) ? actions.dblclick :
(event == button_event_t::LongClick) ? actions.lngclick :
(event == button_event_t::LongLongClick) ? actions.lnglngclick :
(event == button_event_t::TripleClick) ? actions.trplclick : 0U
(event == button_event_t::TripleClick) ? actions.trplclick : ButtonAction::None
);
}
@ -181,7 +208,7 @@ constexpr button_event_t _buttonMapReleased(uint8_t count, unsigned long length,
);
}
button_actions_t _buttonConstructActions(unsigned char index) {
ButtonActions _buttonConstructActions(unsigned char index) {
return {
_buttonPress(index),
_buttonRelease(index),
@ -222,12 +249,12 @@ button_event_delays_t::button_event_delays_t(unsigned long debounce, unsigned lo
lnglngclick(lnglngclick)
{}
button_t::button_t(button_actions_t&& actions_, button_event_delays_t&& delays_) :
button_t::button_t(ButtonActions&& actions_, button_event_delays_t&& delays_) :
actions(std::move(actions_)),
event_delays(std::move(delays_))
{}
button_t::button_t(BasePinPtr&& pin, const debounce_event::types::Config& config, button_actions_t&& actions_, button_event_delays_t&& delays_) :
button_t::button_t(BasePinPtr&& pin, const debounce_event::types::Config& config, ButtonActions&& actions_, button_event_delays_t&& delays_) :
event_emitter(std::make_unique<debounce_event::EventEmitter>(std::move(pin), config, delays_.debounce, delays_.repeat)),
actions(std::move(actions_)),
event_delays(std::move(delays_))
@ -382,14 +409,22 @@ bool _buttonWebSocketOnKeyCheck(const char * key, JsonVariant&) {
#endif // WEB_SUPPORT
ButtonCustomAction _button_custom_action { nullptr };
void buttonSetCustomAction(ButtonCustomAction action) {
_button_custom_action = action;
}
bool buttonState(unsigned char id) {
if (id >= _buttons.size()) return false;
return _buttons[id].state();
return (id < _buttons.size())
? _buttons[id].state()
: false;
}
button_action_t buttonAction(unsigned char id, const button_event_t event) {
if (id >= _buttons.size()) return 0;
return _buttonDecodeEventAction(_buttons[id].actions, event);
ButtonAction buttonAction(unsigned char id, const button_event_t event) {
return (id < _buttons.size())
? _buttonDecodeEventAction(_buttons[id].actions, event)
: ButtonAction::None;
}
// Note that we don't directly return F(...), but use a temporary to assign it conditionally
@ -442,21 +477,28 @@ unsigned char _buttonRelaySetting(unsigned char id) {
return relays[id];
}
void _buttonRelayAction(unsigned char id, button_action_t action) {
void _buttonRelayAction(unsigned char id, ButtonAction action) {
auto relayId = _buttonRelaySetting(id);
switch (action) {
case BUTTON_ACTION_TOGGLE:
case ButtonAction::Toggle:
relayToggle(relayId);
break;
case BUTTON_ACTION_ON:
case ButtonAction::On:
relayStatus(relayId, true);
break;
case BUTTON_ACTION_OFF:
case ButtonAction::Off:
relayStatus(relayId, false);
break;
case ButtonAction::Pulse:
// TODO
break;
default:
break;
}
}
@ -470,75 +512,88 @@ void buttonEvent(unsigned char id, button_event_t event) {
if (event == button_event_t::None) return;
auto& button = _buttons[id];
auto action = _buttonDecodeEventAction(button.actions, event);
#if BROKER_SUPPORT
ButtonBroker::Publish(id, event);
#endif
#if BROKER_SUPPORT
ButtonBroker::Publish(id, event);
#endif
#if MQTT_SUPPORT
if (action || _buttons_mqtt_send_all[id]) {
mqttSend(MQTT_TOPIC_BUTTON, id, _buttonEventString(event).c_str(), false, _buttons_mqtt_retain[id]);
}
#endif
#if MQTT_SUPPORT
if ((action != ButtonAction::None) || _buttons_mqtt_send_all[id]) {
mqttSend(MQTT_TOPIC_BUTTON, id, _buttonEventString(event).c_str(), false, _buttons_mqtt_retain[id]);
}
#endif
switch (action) {
#if RELAY_SUPPORT
case BUTTON_ACTION_TOGGLE:
case BUTTON_ACTION_ON:
case BUTTON_ACTION_OFF:
_buttonRelayAction(id, action);
break;
#endif
#if RELAY_SUPPORT
case ButtonAction::Toggle:
case ButtonAction::On:
case ButtonAction::Off:
case ButtonAction::Pulse:
_buttonRelayAction(id, action);
break;
#endif
case BUTTON_ACTION_AP:
if (wifiState() & WIFI_STATE_AP) {
wifiStartSTA();
} else {
wifiStartAP();
}
break;
case ButtonAction::AccessPoint:
if (wifiState() & WIFI_STATE_AP) {
wifiStartSTA();
} else {
wifiStartAP();
}
break;
case BUTTON_ACTION_RESET:
deferredReset(100, CUSTOM_RESET_HARDWARE);
break;
case ButtonAction::Reset:
deferredReset(100, CUSTOM_RESET_HARDWARE);
break;
case BUTTON_ACTION_FACTORY:
DEBUG_MSG_P(PSTR("\n\nFACTORY RESET\n\n"));
resetSettings();
deferredReset(100, CUSTOM_RESET_FACTORY);
break;
case ButtonAction::FactoryReset:
DEBUG_MSG_P(PSTR("\n\nFACTORY RESET\n\n"));
resetSettings();
deferredReset(100, CUSTOM_RESET_FACTORY);
break;
#if defined(JUSTWIFI_ENABLE_WPS)
case BUTTON_ACTION_WPS:
wifiStartWPS();
break;
#endif // defined(JUSTWIFI_ENABLE_WPS)
case ButtonAction::Wps:
#if defined(JUSTWIFI_ENABLE_WPS)
wifiStartWPS();
#endif
break;
#if defined(JUSTWIFI_ENABLE_SMARTCONFIG)
case BUTTON_ACTION_SMART_CONFIG:
wifiStartSmartConfig();
break;
#endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG)
case ButtonAction::SmartConfig:
#if defined(JUSTWIFI_ENABLE_SMARTCONFIG)
wifiStartSmartConfig();
#endif
break;
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
case BUTTON_ACTION_DIM_UP:
lightBrightnessStep(1);
lightUpdate();
break;
case ButtonAction::BrightnessIncrease:
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
lightBrightnessStep(1);
lightUpdate();
#endif
break;
case BUTTON_ACTION_DIM_DOWN:
lightBrightnessStep(-1);
lightUpdate();
break;
#endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
case ButtonAction::BrightnessDecrease:
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
lightBrightnessStep(-1);
lightUpdate();
#endif
break;
#if THERMOSTAT_DISPLAY_SUPPORT
case BUTTON_ACTION_DISPLAY_ON:
displayOn();
break;
#endif
case ButtonAction::DisplayOn:
#if THERMOSTAT_DISPLAY_SUPPORT
displayOn();
#endif
break;
case ButtonAction::Custom:
if (_button_custom_action) {
_button_custom_action(id);
}
break;
case ButtonAction::None:
break;
}
@ -746,8 +801,8 @@ BasePinPtr _buttonGpioPin(unsigned char index, ButtonProvider provider) {
return result;
}
inline button_actions_t _buttonActions(unsigned char index) {
button_actions_t actions {
ButtonActions _buttonActions(unsigned char index) {
return {
getSetting({"btnPress", index}, _buttonPress(index)),
getSetting({"btnRlse", index}, _buttonRelease(index)),
getSetting({"btnClick", index}, _buttonClick(index)),
@ -756,20 +811,17 @@ inline button_actions_t _buttonActions(unsigned char index) {
getSetting({"btnLLclk", index}, _buttonLongLongClick(index)),
getSetting({"btnTclk", index}, _buttonTripleClick(index))
};
return actions;
}
// Note that we use settings without indexes as default values
// Note that we use settings without indexes as default values to preserve backwards compatibility
button_event_delays_t _buttonDelays(unsigned char index) {
button_event_delays_t delays {
return {
_buttonGetSetting("btnDebDel", index, _buttonDebounceDelay(index)),
_buttonGetSetting("btnRepDel", index, _buttonRepeatDelay(index)),
_buttonGetSetting("btnLclkDel", index, _buttonLongClickDelay(index)),
_buttonGetSetting("btnLLclkDel", index, _buttonLongLongClickDelay(index)),
};
return delays;
}
bool _buttonSetupProvider(unsigned char index, ButtonProvider provider) {


+ 38
- 15
code/espurna/button.h View File

@ -17,10 +17,12 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <memory>
constexpr size_t ButtonsPresetMax = 8;
constexpr size_t ButtonsMax = 32;
constexpr size_t ButtonsActionMax { 255ul };
using button_action_t = uint8_t;
constexpr size_t ButtonsPresetMax { 8ul };
constexpr size_t ButtonsMax { 32ul };
using ButtonCustomAction = void(*)(unsigned char id);
enum class ButtonProvider : int {
None,
@ -39,14 +41,33 @@ enum class button_event_t {
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;
button_action_t lnglngclick;
button_action_t trplclick;
// button actions, limited to 8-bit number (0b11111111 / 0xff / 255)
enum class ButtonAction : uint8_t {
None,
Toggle,
On,
Off,
AccessPoint,
Reset,
Pulse,
FactoryReset,
Wps,
SmartConfig,
BrightnessIncrease,
BrightnessDecrease,
DisplayOn,
Custom
};
struct ButtonActions {
ButtonAction pressed;
ButtonAction released;
ButtonAction click;
ButtonAction dblclick;
ButtonAction lngclick;
ButtonAction lnglngclick;
ButtonAction trplclick;
};
struct button_event_delays_t {
@ -60,23 +81,25 @@ struct button_event_delays_t {
};
struct button_t {
button_t(button_actions_t&& actions, button_event_delays_t&& delays);
button_t(ButtonActions&& actions, button_event_delays_t&& delays);
button_t(BasePinPtr&& pin, const debounce_event::types::Config& config,
button_actions_t&& actions, button_event_delays_t&& delays);
ButtonActions&& actions, button_event_delays_t&& delays);
bool state();
button_event_t loop();
std::unique_ptr<debounce_event::EventEmitter> event_emitter;
button_actions_t actions;
ButtonActions actions;
button_event_delays_t event_delays;
};
BrokerDeclare(ButtonBroker, void(unsigned char id, button_event_t event));
void buttonSetCustomAction(ButtonCustomAction);
bool buttonState(unsigned char id);
button_action_t buttonAction(unsigned char id, const button_event_t event);
ButtonAction buttonAction(unsigned char id, const button_event_t event);
void buttonEvent(unsigned char id, button_event_t event);


+ 7
- 7
code/espurna/button_config.h View File

@ -59,7 +59,7 @@ constexpr int _buttonConfigBitmask(unsigned char index) {
);
}
constexpr unsigned char _buttonRelease(unsigned char index) {
constexpr ButtonAction _buttonRelease(unsigned char index) {
return (
(index == 0) ? BUTTON1_RELEASE :
(index == 1) ? BUTTON2_RELEASE :
@ -72,7 +72,7 @@ constexpr unsigned char _buttonRelease(unsigned char index) {
);
}
constexpr unsigned char _buttonPress(unsigned char index) {
constexpr ButtonAction _buttonPress(unsigned char index) {
return (
(index == 0) ? BUTTON1_PRESS :
(index == 1) ? BUTTON2_PRESS :
@ -85,7 +85,7 @@ constexpr unsigned char _buttonPress(unsigned char index) {
);
}
constexpr unsigned char _buttonClick(unsigned char index) {
constexpr ButtonAction _buttonClick(unsigned char index) {
return (
(index == 0) ? BUTTON1_CLICK :
(index == 1) ? BUTTON2_CLICK :
@ -98,7 +98,7 @@ constexpr unsigned char _buttonClick(unsigned char index) {
);
}
constexpr unsigned char _buttonDoubleClick(unsigned char index) {
constexpr ButtonAction _buttonDoubleClick(unsigned char index) {
return (
(index == 0) ? BUTTON1_DBLCLICK :
(index == 1) ? BUTTON2_DBLCLICK :
@ -111,7 +111,7 @@ constexpr unsigned char _buttonDoubleClick(unsigned char index) {
);
}
constexpr unsigned char _buttonTripleClick(unsigned char index) {
constexpr ButtonAction _buttonTripleClick(unsigned char index) {
return (
(index == 0) ? BUTTON1_TRIPLECLICK :
(index == 1) ? BUTTON2_TRIPLECLICK :
@ -124,7 +124,7 @@ constexpr unsigned char _buttonTripleClick(unsigned char index) {
);
}
constexpr unsigned char _buttonLongClick(unsigned char index) {
constexpr ButtonAction _buttonLongClick(unsigned char index) {
return (
(index == 0) ? BUTTON1_LNGCLICK :
(index == 1) ? BUTTON2_LNGCLICK :
@ -137,7 +137,7 @@ constexpr unsigned char _buttonLongClick(unsigned char index) {
);
}
constexpr unsigned char _buttonLongLongClick(unsigned char index) {
constexpr ButtonAction _buttonLongLongClick(unsigned char index) {
return (
(index == 0) ? BUTTON1_LNGLNGCLICK :
(index == 1) ? BUTTON2_LNGLNGCLICK :


+ 8
- 0
code/espurna/config/hardware.h View File

@ -1014,10 +1014,18 @@
#define IFAN_SUPPORT 1
// These buttons are triggered by the remote
// iFan module adds a custom button handler
#define BUTTON1_PIN 0
#define BUTTON1_CLICK BUTTON_ACTION_TOGGLE
#define BUTTON2_PIN 9
#define BUTTON2_CLICK BUTTON_ACTION_CUSTOM
#define BUTTON3_PIN 10
#define BUTTON3_CLICK BUTTON_ACTION_CUSTOM
#define BUTTON4_PIN 14
#define BUTTON4_CLICK BUTTON_ACTION_CUSTOM
// Only one relay by default, controlling the ON / OFF
#define RELAY1_PIN 12


+ 16
- 15
code/espurna/config/types.h View File

@ -29,21 +29,22 @@
// BUTTONS
//------------------------------------------------------------------------------
// 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
#define BUTTON_ACTION_OFF 3u
#define BUTTON_ACTION_AP 4u
#define BUTTON_ACTION_RESET 5u
#define BUTTON_ACTION_PULSE 6u
#define BUTTON_ACTION_FACTORY 7u
#define BUTTON_ACTION_WPS 8u
#define BUTTON_ACTION_SMART_CONFIG 9u
#define BUTTON_ACTION_DIM_UP 10u
#define BUTTON_ACTION_DIM_DOWN 11u
#define BUTTON_ACTION_DISPLAY_ON 12u
#define BUTTON_ACTION_MAX 255u
#define BUTTON_ACTION_NONE ButtonAction::None
#define BUTTON_ACTION_TOGGLE ButtonAction::Toggle
#define BUTTON_ACTION_ON ButtonAction::On
#define BUTTON_ACTION_OFF ButtonAction::Off
#define BUTTON_ACTION_AP ButtonAction::AccessPoint
#define BUTTON_ACTION_RESET ButtonAction::Reset
#define BUTTON_ACTION_PULSE ButtonAction::Pulse
#define BUTTON_ACTION_FACTORY ButtonAction::FactoryReset
#define BUTTON_ACTION_WPS ButtonAction::Wps
#define BUTTON_ACTION_SMART_CONFIG ButtonAction::SmartConfig
#define BUTTON_ACTION_DIM_UP ButtonAction::BrightnessIncrease
#define BUTTON_ACTION_DIM_DOWN ButtonAction::BrightnessDecrease
#define BUTTON_ACTION_DISPLAY_ON ButtonAction::DisplayOn
#define BUTTON_ACTION_CUSTOM ButtonAction::Custom
#define BUTTON_ACTION_MAX ButtonsActionMax
// Deprecated: legacy mapping, changed to action from above
#define BUTTON_MODE_NONE BUTTON_ACTION_NONE


+ 11
- 18
code/espurna/ifan.cpp View File

@ -101,10 +101,9 @@ constexpr unsigned long DefaultSaveDelay { 1000ul };
constexpr unsigned char DefaultRelayId { 0u };
constexpr unsigned char DefaultStateButton { 0u };
constexpr unsigned char DefaultLowButton { 1u };
constexpr unsigned char DefaultMediumButton { 2u };
constexpr unsigned char DefaultHighButton { 3u };
constexpr unsigned char DefaultLowButtonId { 1u };
constexpr unsigned char DefaultMediumButtonId { 2u };
constexpr unsigned char DefaultHighButtonId { 3u };
// We expect to write a specific 'mask' via GPIO LOW & HIGH to set the speed
// Sync up with the relay and write it on ON / OFF status events
@ -128,10 +127,10 @@ StatePins statePins() {
struct Config {
unsigned long save { DefaultSaveDelay };
unsigned char relayId { RELAY_NONE };
unsigned char buttonLowId { RELAY_NONE };
unsigned char buttonMediumId { RELAY_NONE };
unsigned char buttonHighId { RELAY_NONE };
unsigned char relayId { DefaultRelayId };
unsigned char buttonLowId { DefaultLowButtonId };
unsigned char buttonMediumId { DefaultMediumButtonId };
unsigned char buttonHighId { DefaultHighButtonId };
Speed speed { Speed::Off };
StatePins state_pins;
};
@ -140,9 +139,9 @@ Config readSettings() {
return {
getSetting("ifanSave", DefaultSaveDelay),
getSetting("ifanRelayId", DefaultRelayId),
getSetting("ifanBtnLowId", DefaultMediumButton),
getSetting("ifanBtnLowId", DefaultMediumButton),
getSetting("ifanBtnHighId", DefaultHighButton),
getSetting("ifanBtnLowId", DefaultLowButtonId),
getSetting("ifanBtnLowId", DefaultMediumButtonId),
getSetting("ifanBtnHighId", DefaultHighButtonId),
getSetting("ifanSpeed", Speed::Medium)
};
}
@ -299,13 +298,7 @@ void setup() {
espurnaRegisterReload(configure);
#if BUTTON_SUPPORT
ButtonBroker::Register([](unsigned char id, button_event_t event) {
// TODO: add special 'custom' action for buttons, and trigger via basic callback?
// that way we don't depend on the event type and directly trigger with whatever cfg says
if (event != button_event_t::Click) {
return;
}
buttonSetCustomAction([](unsigned char id) {
if (config.buttonLowId == id) {
setSpeed(Speed::Low);
} else if (config.buttonMediumId == id) {


Loading…
Cancel
Save