Browse Source

Button pin provider & runtime settings (#2162)

* wip

* cleanup buttons-through-serial code, remove hw mention from button module

* remove wip

* implement mqtt settings

* fixup struct members, dual no longer allocates debouncer

* add missing debounceevent lib

* fix missing event_handler, update names

* fix namespace

* drop lib

* fix int<->bool comparison

* Move gpio16 handling from DigitalPin to EventHandler

* Cleanup debounceevent headers

* Don't expect system headers to be included

* re 70b54c489f - no allocation, for real

* Adjust settings names

* dont retain by default

* unused

* typo

* Fix length type (ref 6017ad9474)

* Move pin class outside of debounce lib, lowercase ns

* move event handling inside of button_t

* refactor config. ..._MODE -> _CONFIG, ..._MODE_... -> ..._ACTION_...

* fix test

* naming

* move indexed value to header

* refactor actions into direct opts

* fix webui, fix buttons not respecting old user setting

* change button config format from bitmask to a struct, adjust settings conversion

* proxy some more header defautls, fix web kv

* gpiopin

* adjust webui func to support every setting

* clarify single-return event->string

* fix dual setting

* fix dual packet condition, de-duplicate funcs

* fix bogus warning
mcspr-patch-1
Max Prokhorov 4 years ago
committed by GitHub
parent
commit
ba3e6267e6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 21335 additions and 20243 deletions
  1. +157
    -0
      code/espurna/DebounceEvent.cpp
  2. +7
    -0
      code/espurna/board.ino
  3. +49
    -17
      code/espurna/button.h
  4. +542
    -163
      code/espurna/button.ino
  5. +102
    -44
      code/espurna/button_config.h
  6. +2
    -2
      code/espurna/config/all.h
  7. +228
    -64
      code/espurna/config/defaults.h
  8. +15
    -2
      code/espurna/config/dependencies.h
  9. +50
    -0
      code/espurna/config/deprecated.h
  10. +15
    -4
      code/espurna/config/general.h
  11. +291
    -279
      code/espurna/config/hardware.h
  12. +57
    -39
      code/espurna/config/types.h
  13. BIN
      code/espurna/data/index.all.html.gz
  14. BIN
      code/espurna/data/index.light.html.gz
  15. BIN
      code/espurna/data/index.lightfox.html.gz
  16. BIN
      code/espurna/data/index.rfbridge.html.gz
  17. BIN
      code/espurna/data/index.rfm69.html.gz
  18. BIN
      code/espurna/data/index.sensor.html.gz
  19. BIN
      code/espurna/data/index.small.html.gz
  20. BIN
      code/espurna/data/index.thermostat.html.gz
  21. +13
    -0
      code/espurna/gpio.h
  22. +20
    -0
      code/espurna/gpio.ino
  23. +28
    -26
      code/espurna/ir.ino
  24. +93
    -93
      code/espurna/ir_button.h
  25. +23
    -0
      code/espurna/libs/BasePin.h
  26. +123
    -0
      code/espurna/libs/DebounceEvent.h
  27. +1
    -1
      code/espurna/lightfox.ino
  28. +2547
    -2546
      code/espurna/static/index.all.html.gz.h
  29. +2353
    -2352
      code/espurna/static/index.light.html.gz.h
  30. +2415
    -2413
      code/espurna/static/index.lightfox.html.gz.h
  31. +1985
    -1983
      code/espurna/static/index.rfbridge.html.gz.h
  32. +3330
    -3329
      code/espurna/static/index.rfm69.html.gz.h
  33. +2509
    -2508
      code/espurna/static/index.sensor.html.gz.h
  34. +2403
    -2401
      code/espurna/static/index.small.html.gz.h
  35. +1969
    -1967
      code/espurna/static/index.thermostat.html.gz.h
  36. +0
    -1
      code/espurna/ws.ino
  37. +7
    -7
      code/html/index.html
  38. +0
    -1
      code/platformio.ini
  39. +1
    -1
      code/test/build/basic.h

+ 157
- 0
code/espurna/DebounceEvent.cpp View File

@ -0,0 +1,157 @@
/*
Original code:
Debounce buttons and trigger events
Copyright (C) 2015-2018 by Xose Pérez <xose dot perez at gmail dot com>
The DebounceEvent library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The DebounceEvent library 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the DebounceEvent library. If not, see <http://www.gnu.org/licenses/>.
----------------------------------------------------------------------------------
Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
Modified to include generic INPUT / OUTPUT pin support through a custom interface.
Definitions are incompatible with DebounceEvent, you should not include it's headers.
*/
#include <functional>
#include <memory>
#include "libs/DebounceEvent.h"
namespace debounce_event {
EventEmitter::EventEmitter(types::Pin pin, types::EventHandler callback, const types::Config& config, unsigned long debounce_delay, unsigned long repeat) :
_pin(pin),
_callback(callback),
_config(config),
_is_switch(config.mode == types::Mode::Switch),
_default_status(config.default_state == types::DefaultState::High),
_delay(debounce_delay),
_repeat(repeat),
_status(false),
_ready(false),
_reset_count(true),
_event_start(0),
_event_length(0),
_event_count(0)
{
if (!pin) return;
if (_config.pin_mode == types::PinMode::InputPullup) {
_pin->pinMode(INPUT_PULLUP);
} else if (_config.pin_mode == types::PinMode::InputPulldown) {
// ESP8266 does not have INPUT_PULLDOWN definition, and instead
// has a GPIO16-specific INPUT_PULLDOWN_16:
// - https://github.com/esp8266/Arduino/issues/478
// - https://github.com/esp8266/Arduino/commit/1b3581d55ebf0f8c91e081f9af4cf7433d492ec9
#ifdef ESP8266
if (_pin->pin == 16) {
_pin->pinMode(_default_status ? INPUT : INPUT_PULLDOWN_16);
} else {
_pin->pinMode(INPUT);
}
#else
_pin->pinMode(INPUT_PULLDOWN);
#endif
} else {
_pin->pinMode(INPUT);
}
_status = _is_switch ? (_pin->digitalRead() == (HIGH)) : _default_status;
}
EventEmitter::EventEmitter(types::Pin pin, const types::Config& config, unsigned long delay, unsigned long repeat) :
EventEmitter(pin, nullptr, config, delay, repeat)
{}
bool EventEmitter::isPressed() {
return (_status != _default_status);
}
const types::Pin EventEmitter::getPin() const {
return _pin;
}
const types::Config EventEmitter::getConfig() const {
return _config;
}
unsigned long EventEmitter::getEventLength() {
return _event_length;
}
unsigned long EventEmitter::getEventCount() {
return _event_count;
}
// TODO: current implementation allows pin == nullptr
types::Event EventEmitter::loop() {
static_assert((HIGH) == 1, "Arduino API HIGH is not 1");
static_assert((LOW) == 0, "Arduino API LOW is not 0");
auto event = types::EventNone;
bool status = _pin->digitalRead() == (HIGH);
if (status != _status) {
// TODO: check each loop instead of blocking?
auto start = millis();
while (millis() - start < _delay) delay(1);
status = _pin->digitalRead() == (HIGH);
if (status != _status) {
_status = !_status;
if (_is_switch) {
event = types::EventChanged;
} else {
if (_status == _default_status) {
_event_length = millis() - _event_start;
_ready = true;
} else {
event = types::EventPressed;
_event_start = millis();
_event_length = 0;
if (_reset_count) {
_event_count = 1;
_reset_count = false;
} else {
++_event_count;
}
_ready = false;
}
}
}
}
if (_ready && (millis() - _event_start > _repeat)) {
_ready = false;
_reset_count = true;
event = types::EventReleased;
}
if (_callback && (event != types::EventNone)) {
_callback(*this, event, _event_count, _event_length);
}
return event;
}
} // namespace debounce_event

+ 7
- 0
code/espurna/board.ino View File

@ -19,7 +19,11 @@ PROGMEM const char espurna_modules[] =
"BROKER "
#endif
#if BUTTON_SUPPORT
#if BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC
"BUTTON "
#else
"BUTTON_DUAL "
#endif
#endif
#if DEBUG_SERIAL_SUPPORT
"DEBUG_SERIAL "
@ -81,6 +85,9 @@ PROGMEM const char espurna_modules[] =
#if RF_SUPPORT
"RF "
#endif
#if RPN_RULES_SUPPORT
"RPN_RULES "
#endif
#if SCHEDULER_SUPPORT
"SCHEDULER "
#endif


+ 49
- 17
code/espurna/button.h View File

@ -8,34 +8,66 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#pragma once
#include <DebounceEvent.h>
#include "libs/BasePin.h"
#include "libs/DebounceEvent.h"
struct button_t {
#include <memory>
constexpr size_t ButtonsPresetMax = 8;
constexpr size_t ButtonsMax = 32;
// TODO: dblclick and debounce delays - right now a global setting, independent of ID
static unsigned long DebounceDelay;
static unsigned long DblclickDelay;
enum class button_event_t {
None = 0,
Pressed = 1,
Click = 2,
DoubleClick = 3,
LongClick = 4,
LongLongClick = 5,
TripleClick = 6
};
// Use built-in indexed definitions to configure DebounceEvent
button_t(unsigned char index);
struct button_actions_t {
uint16_t pressed;
uint16_t click;
uint16_t dblclick;
uint16_t lngclick;
uint16_t lnglngclick;
uint16_t trplclick;
};
// Provide custom DebounceEvent parameters instead
button_t(unsigned char pin, unsigned char mode, unsigned long actions, unsigned char relayID);
struct button_event_delays_t {
button_event_delays_t();
button_event_delays_t(unsigned long debounce, unsigned long repeat, unsigned long lngclick, unsigned long lnglngclick);
const unsigned long debounce;
const unsigned long repeat;
const unsigned long lngclick;
const unsigned long lnglngclick;
};
struct button_t {
button_t(unsigned char relayID, const button_actions_t& actions, const button_event_delays_t& delays);
button_t(std::shared_ptr<BasePin> pin, const debounce_event::types::Config& config,
unsigned char relayID, const button_actions_t& actions, const button_event_delays_t& delays);
bool state();
button_event_t loop();
std::unique_ptr<debounce_event::EventEmitter> event_emitter;
const button_event_delays_t event_delays;
const button_actions_t actions;
const unsigned char relayID;
std::unique_ptr<DebounceEvent> event;
unsigned long actions;
unsigned char relayID;
};
bool buttonState(unsigned char id);
unsigned char buttonAction(unsigned char id, unsigned char event);
void buttonMQTT(unsigned char id, uint8_t event);
void buttonEvent(unsigned char id, unsigned char event);
uint16_t buttonAction(unsigned char id, const button_event_t event);
unsigned char buttonAdd(unsigned char pin, unsigned char mode, unsigned long actions, unsigned char relayID = RELAY_NONE);
void buttonMQTT(unsigned char id, button_event_t event);
void buttonEvent(unsigned char id, button_event_t event);
unsigned char buttonCount();
void buttonSetup();

+ 542
- 163
code/espurna/button.ino View File

@ -8,10 +8,12 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if BUTTON_SUPPORT
#include <DebounceEvent.h>
#include <bitset>
#include <memory>
#include <vector>
#include "compat.h"
#include "gpio.h"
#include "system.h"
#include "relay.h"
#include "light.h"
@ -19,38 +21,197 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "button.h"
#include "button_config.h"
#include "libs/DebounceEvent.h"
// TODO: if we are using such conversion helpers across the codebase, should convert() be in internal ns?
namespace settings {
namespace internal {
template<>
debounce_event::types::Mode convert(const String& value) {
switch (value.toInt()) {
case 1:
return debounce_event::types::Mode::Switch;
case 0:
default:
return debounce_event::types::Mode::Pushbutton;
}
}
template<>
debounce_event::types::DefaultState convert(const String& value) {
switch (value.toInt()) {
case 0:
return debounce_event::types::DefaultState::Low;
case 1:
default:
return debounce_event::types::DefaultState::High;
}
}
template<>
debounce_event::types::PinMode convert(const String& value) {
switch (value.toInt()) {
case 1:
return debounce_event::types::PinMode::InputPullup;
case 2:
return debounce_event::types::PinMode::InputPulldown;
case 0:
default:
return debounce_event::types::PinMode::Input;
}
}
} // namespace settings::internal
} // namespace settings
// -----------------------------------------------------------------------------
constexpr const debounce_event::types::Config _buttonDecodeConfigBitmask(const unsigned char bitmask) {
return {
((bitmask & ButtonMask::Pushbutton)
? debounce_event::types::Mode::Pushbutton
: debounce_event::types::Mode::Switch),
((bitmask & ButtonMask::DefaultHigh)
? debounce_event::types::DefaultState::High
: debounce_event::types::DefaultState::Low),
((bitmask & ButtonMask::SetPullup)
? debounce_event::types::PinMode::InputPullup : (bitmask & ButtonMask::SetPulldown)
? debounce_event::types::PinMode::InputPullup : debounce_event::types::PinMode::Input)
};
}
constexpr const uint16_t _buttonDecodeEventAction(const button_actions_t& actions, button_event_t event) {
return (
(event == button_event_t::Pressed) ? actions.pressed :
(event == button_event_t::Click) ? actions.click :
(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
);
}
constexpr const button_event_t _buttonMapReleased(uint8_t count, unsigned long length, unsigned long lngclick_delay, unsigned long lnglngclick_delay) {
return (
(1 == count) ? (
(length > lnglngclick_delay) ? button_event_t::LongLongClick :
(length > lngclick_delay) ? button_event_t::LongClick : button_event_t::Click
) :
(2 == count) ? button_event_t::DoubleClick :
(3 == count) ? button_event_t::TripleClick :
button_event_t::None
);
}
button_actions_t _buttonConstructActions(unsigned char index) {
return {
_buttonPress(index),
_buttonClick(index),
_buttonDoubleClick(index),
_buttonLongClick(index),
_buttonLongLongClick(index),
_buttonTripleClick(index)
};
}
debounce_event::types::Config _buttonConfig(unsigned char index) {
const auto config = _buttonDecodeConfigBitmask(_buttonConfigBitmask(index));
return {
getSetting({"btnMode", index}, config.mode),
getSetting({"btnDefState", index}, config.default_state),
getSetting({"btnPinMode", index}, config.pin_mode)
};
}
// -----------------------------------------------------------------------------
// TODO: dblclick and debounce delays - right now a global setting, independent of ID
unsigned long button_t::DebounceDelay = BUTTON_DEBOUNCE_DELAY;
unsigned long button_t::DblclickDelay = BUTTON_DBLCLICK_DELAY;
button_event_delays_t::button_event_delays_t() :
debounce(_buttonDebounceDelay()),
repeat(_buttonRepeatDelay()),
lngclick(_buttonLongClickDelay()),
lnglngclick(_buttonLongLongClickDelay())
{}
button_event_delays_t::button_event_delays_t(unsigned long debounce, unsigned long repeat, unsigned long lngclick, unsigned long lnglngclick) :
debounce(debounce),
repeat(repeat),
lngclick(lngclick),
lnglngclick(lnglngclick)
{}
button_t::button_t(unsigned char pin, unsigned char mode, unsigned long actions, unsigned char relayID) :
event(new DebounceEvent(pin, mode, DebounceDelay, DblclickDelay)),
button_t::button_t(unsigned char relayID, const button_actions_t& actions, const button_event_delays_t& delays) :
event_emitter(nullptr),
event_delays(delays),
actions(actions),
relayID(relayID)
{}
button_t::button_t(unsigned char index) :
button_t(_buttonPin(index), _buttonMode(index), _buttonConstructActions(index), _buttonRelay(index))
button_t::button_t(std::shared_ptr<BasePin> pin, const debounce_event::types::Config& config, unsigned char relayID, const button_actions_t& actions, const button_event_delays_t& delays) :
event_emitter(std::make_unique<debounce_event::EventEmitter>(pin, config, delays.debounce, delays.repeat)),
event_delays(delays),
actions(actions),
relayID(relayID)
{}
bool button_t::state() {
return event->pressed();
return event_emitter->isPressed();
}
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) {
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(),
event_emitter->getEventLength(),
event_delays.lngclick,
event_delays.lnglngclick
);
}
case debounce_event::types::EventNone:
default:
break;
}
return button_event_t::None;
}
std::vector<button_t> _buttons;
// -----------------------------------------------------------------------------
unsigned char buttonCount() {
return _buttons.size();
}
#if MQTT_SUPPORT
void buttonMQTT(unsigned char id, uint8_t event) {
std::bitset<ButtonsMax> _buttons_mqtt_send_all(
(1 == BUTTON_MQTT_SEND_ALL_EVENTS) ? 0xFFFFFFFFUL : 0UL
);
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(event, payload, 10);
mqttSend(MQTT_TOPIC_BUTTON, id, payload, false, false); // 1st bool = force, 2nd = retain
itoa(_buttonEventNumber(event), payload, 10);
// mqttSend(topic, id, payload, force, retain)
mqttSend(MQTT_TOPIC_BUTTON, id, payload, false, _buttons_mqtt_retain[id]);
}
#endif
@ -63,6 +224,101 @@ void _buttonWebSocketOnVisible(JsonObject& root) {
}
}
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL)
void _buttonWebSocketOnConnected(JsonObject& root) {
root["btnRepDel"] = getSetting("btnRepDel", _buttonRepeatDelay());
}
#else
void _buttonWebSocketOnConnected(JsonObject& root) {
root["btnRepDel"] = getSetting("btnRepDel", _buttonRepeatDelay());
// XXX: unused! pending webui changes
#if 0
if (buttonCount() < 1) return;
JsonObject& module = root.createNestedObject("btn");
// TODO: hardware can sometimes use a different event source
// e.g. Sonoff Dual does not need `Pin`, `Mode` or any of `Del`
// TODO: schema names are uppercase to easily match settings?
// TODO: schema name->type map to generate WebUI elements?
JsonArray& schema = module.createNestedArray("_schema");
schema.add("GPIO");
schema.add("Mode");
schema.add("DefState");
schema.add("PinMode");
schema.add("Relay");
schema.add("Press");
schema.add("Click");
schema.add("Dclk");
schema.add("Lclk");
schema.add("LLclk");
schema.add("Tclk");
schema.add("DebDel");
schema.add("RepDel");
schema.add("LclkDel");
schema.add("LLclkDel");
#if MQTT_SUPPORT
schema.add("MqttSendAll");
schema.add("MqttRetain");
#endif
JsonArray& buttons = module.createNestedArray("list");
for (unsigned char i=0; i<buttonCount(); i++) {
JsonArray& button = buttons.createNestedArray();
// TODO: configure PIN object instead of button specifically, link PIN<->BUTTON
if (_buttons[i].getPin()) {
button.add(getSetting({"btnGPIO", index}, _buttonPin(index)));
const auto config = _buttonConfig(index);
button.add(static_cast<int>(config.mode));
button.add(static_cast<int>(config.default_state));
button.add(static_cast<int>(config.pin_mode));
} else {
button.add(GPIO_NONE);
button.add(static_cast<int>(BUTTON_PUSHBUTTON));
button.add(0);
button.add(0);
button.add(0);
}
button.add(_buttons[i].relayID);
button.add(_buttons[i].actions.pressed);
button.add(_buttons[i].actions.click);
button.add(_buttons[i].actions.dblclick);
button.add(_buttons[i].actions.lngclick);
button.add(_buttons[i].actions.lnglngclick);
button.add(_buttons[i].actions.trplclick);
button.add(_buttons[i].event_delays.debounce);
button.add(_buttons[i].event_delays.repeat);
button.add(_buttons[i].event_delays.lngclick);
button.add(_buttons[i].event_delays.lnglngclick);
// TODO: send bitmask as number?
#if MQTT_SUPPORT
button.add(_buttons_mqtt_send_all[i] ? 1 : 0);
button.add(_buttons_mqtt_retain[i] ? 1 : 0);
#endif
}
#endif
}
#endif // BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC
bool _buttonWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
return (strncmp(key, "btn", 3) == 0);
}
@ -74,122 +330,214 @@ bool buttonState(unsigned char id) {
return _buttons[id].state();
}
unsigned char buttonAction(unsigned char id, unsigned char event) {
if (id >= _buttons.size()) return BUTTON_MODE_NONE;
uint16_t buttonAction(unsigned char id, const button_event_t event) {
if (id >= _buttons.size()) return 0;
return _buttonDecodeEventAction(_buttons[id].actions, event);
}
void buttonEvent(unsigned char id, unsigned char event) {
int _buttonEventNumber(button_event_t event) {
return static_cast<int>(event);
}
// Approach based on https://github.com/esp8266/Arduino/pull/6950
// "PROGMEM footprint cleanup for responseCodeToString (#6950)"
// 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");
break;
case button_event_t::Click:
ptr = F("Click");
break;
case button_event_t::DoubleClick:
ptr = F("Double-click");
break;
case button_event_t::LongClick:
ptr = F("Long-click");
break;
case button_event_t::LongLongClick:
ptr = F("Looong-click");
break;
case button_event_t::TripleClick:
ptr = F("Triple-click");
break;
case button_event_t::None:
default:
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) {
DEBUG_MSG_P(PSTR("[BUTTON] Button #%u event %u\n"), id, event);
if (event == 0) return;
DEBUG_MSG_P(PSTR("[BUTTON] Button #%u event %d (%s)\n"),
id, _buttonEventNumber(event), _buttonEventString(event).c_str()
);
if (event == button_event_t::None) return;
auto& button = _buttons[id];
unsigned char action = _buttonDecodeEventAction(button.actions, event);
auto action = _buttonDecodeEventAction(button.actions, event);
#if MQTT_SUPPORT
if (action != BUTTON_MODE_NONE || BUTTON_MQTT_SEND_ALL_EVENTS) {
buttonMQTT(id, event);
}
#endif
#if THERMOSTAT_DISPLAY_SUPPORT
if (BUTTON_MODE_DISPLAY_ON == action) {
displayOn();
if (action || _buttons_mqtt_send_all[id]) {
buttonMQTT(id, event);
}
#endif
if (BUTTON_MODE_TOGGLE == action) {
relayToggle(button.relayID);
}
switch (action) {
case BUTTON_ACTION_TOGGLE:
relayToggle(button.relayID);
break;
if (BUTTON_MODE_ON == action) {
relayStatus(button.relayID, true);
}
case BUTTON_ACTION_ON:
relayStatus(button.relayID, true);
break;
if (BUTTON_MODE_OFF == action) {
relayStatus(button.relayID, false);
}
if (BUTTON_MODE_AP == action) {
if (wifiState() & WIFI_STATE_AP) {
wifiStartSTA();
} else {
wifiStartAP();
}
}
if (BUTTON_MODE_RESET == action) {
deferredReset(100, CUSTOM_RESET_HARDWARE);
}
case BUTTON_ACTION_OFF:
relayStatus(button.relayID, false);
break;
if (BUTTON_MODE_FACTORY == action) {
DEBUG_MSG_P(PSTR("\n\nFACTORY RESET\n\n"));
resetSettings();
deferredReset(100, CUSTOM_RESET_FACTORY);
}
case BUTTON_ACTION_AP:
if (wifiState() & WIFI_STATE_AP) {
wifiStartSTA();
} else {
wifiStartAP();
}
break;
case BUTTON_ACTION_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;
#if defined(JUSTWIFI_ENABLE_WPS)
if (BUTTON_MODE_WPS == action) {
case BUTTON_ACTION_WPS:
wifiStartWPS();
}
break;
#endif // defined(JUSTWIFI_ENABLE_WPS)
#if defined(JUSTWIFI_ENABLE_SMARTCONFIG)
if (BUTTON_MODE_SMART_CONFIG == action) {
case BUTTON_ACTION_SMART_CONFIG:
wifiStartSmartConfig();
}
break;
#endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG)
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
if (BUTTON_MODE_DIM_UP == action) {
lightBrightnessStep(1);
lightUpdate(true, true);
}
if (BUTTON_MODE_DIM_DOWN == action) {
lightBrightnessStep(-1);
lightUpdate(true, true);
}
case BUTTON_ACTION_DIM_UP:
lightBrightnessStep(1);
lightUpdate(true, true);
break;
case BUTTON_ACTION_DIM_DOWN:
lightBrightnessStep(-1);
lightUpdate(true, true);
break;
#endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
}
#if THERMOSTAT_DISPLAY_SUPPORT
case BUTTON_ACTION_DISPLAY_ON:
displayOn();
break;
#endif
unsigned char buttonAdd(unsigned char pin, unsigned char mode, unsigned long actions, unsigned char relayID) {
_buttons.emplace_back(pin, mode, actions, relayID);
return _buttons.size() - 1;
}
}
void buttonSetup() {
}
// Special hardware cases
void _buttonConfigure() {
#if MQTT_SUPPORT
for (unsigned char index = 0; index < _buttons.size(); ++index) {
_buttons_mqtt_send_all[index] = getSetting({"btnMqttSendAll", index}, _buttonMqttSendAllEvents(index));
_buttons_mqtt_retain[index] = getSetting({"btnMqttRetain", index}, _buttonMqttRetain(index));
}
#endif
}
#if defined(ITEAD_SONOFF_DUAL)
// TODO: compatibility proxy, fetch global key before indexed
template<typename T>
unsigned long _buttonGetSetting(const char* key, unsigned char index, T default_value) {
return getSetting(key, getSetting({key, index}, default_value));
}
_buttons.reserve(3);
void buttonSetup() {
buttonAdd(GPIO_NONE, BUTTON_PUSHBUTTON, 0, _buttonRelay(0));
buttonAdd(GPIO_NONE, BUTTON_PUSHBUTTON, 0, _buttonRelay(1));
buttonAdd(GPIO_NONE, BUTTON_PUSHBUTTON, 0, _buttonRelay(2));
// Backwards compatibility
moveSetting("btnDelay", "btnRepDel");
#elif defined(FOXEL_LIGHTFOX_DUAL)
// Special hardware cases
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL)
_buttons.reserve(4);
size_t buttons = 0;
#if BUTTON1_RELAY != RELAY_NONE
++buttons;
#endif
#if BUTTON2_RELAY != RELAY_NONE
++buttons;
#endif
#if BUTTON3_RELAY != RELAY_NONE
++buttons;
#endif
#if BUTTON4_RELAY != RELAY_NONE
++buttons;
#endif
const auto actions = _buttonConstructActions(
BUTTON_MODE_NONE, BUTTON_MODE_TOGGLE, BUTTON_MODE_NONE,
BUTTON_MODE_NONE, BUTTON_MODE_NONE, BUTTON_MODE_NONE
);
_buttons.reserve(buttons);
for (unsigned char id = 0; id < 4; ++id) {
buttonAdd(
GPIO_NONE, BUTTON_PUSHBUTTON,
actions, getSetting({"btnRelay", id}, _buttonRelay(id))
// Ignore real button delays since we don't use them here
const auto delays = button_event_delays_t();
for (unsigned char index = 0; index < buttons; ++index) {
const button_actions_t actions {
BUTTON_ACTION_NONE,
// The only generated event is ::Click
getSetting({"btnClick", index}, _buttonClick(index)),
BUTTON_ACTION_NONE,
BUTTON_ACTION_NONE,
BUTTON_ACTION_NONE,
BUTTON_ACTION_NONE
};
_buttons.emplace_back(
getSetting({"btnRelay", index}, _buttonRelay(index)),
actions,
delays
);
}
// Generic GPIO input handlers
#else
#elif BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC
size_t buttons = 0;
@ -220,108 +568,139 @@ void buttonSetup() {
_buttons.reserve(buttons);
// TODO: load based on index
button_t::DebounceDelay = getSetting("btnDebounce", BUTTON_DEBOUNCE_DELAY);
button_t::DblclickDelay = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY);
for (unsigned char id = 0; id < buttons; ++id) {
_buttons.emplace_back(id);
for (unsigned char index = 0; index < buttons; ++index) {
const auto pin = getSetting({"btnGPIO", index}, _buttonPin(index));
if (!gpioValid(pin)) {
break;
}
const auto relayID = getSetting({"btnRelay", index}, _buttonRelay(index));
// TODO: compatibility proxy, fetch global key before indexed
const button_event_delays_t delays {
_buttonGetSetting("btnDebDel", index, _buttonDebounceDelay(index)),
_buttonGetSetting("btnRepDel", index, _buttonRepeatDelay(index)),
_buttonGetSetting("btnLclkDel", index, _buttonLongClickDelay(index)),
_buttonGetSetting("btnLLclkDel", index, _buttonLongLongClickDelay(index)),
};
const button_actions_t actions {
getSetting({"btnPress", index}, _buttonPress(index)),
getSetting({"btnClick", index}, _buttonClick(index)),
getSetting({"btnDclk", index}, _buttonDoubleClick(index)),
getSetting({"btnLclk", index}, _buttonLongClick(index)),
getSetting({"btnLLclk", index}, _buttonLongLongClick(index)),
getSetting({"btnTclk", index}, _buttonTripleClick(index))
};
const auto config = _buttonConfig(index);
// TODO: allow to change GpioPin to something else based on config?
_buttons.emplace_back(
std::make_shared<GpioPin>(pin), config,
relayID, actions, delays
);
}
#endif
_buttonConfigure();
DEBUG_MSG_P(PSTR("[BUTTON] Number of buttons: %u\n"), _buttons.size());
// Websocket Callbacks
#if WEB_SUPPORT
wsRegister()
.onConnected(_buttonWebSocketOnVisible)
.onVisible(_buttonWebSocketOnVisible)
.onKeyCheck(_buttonWebSocketOnKeyCheck);
#endif
// Register loop
// Register system callbacks
espurnaRegisterLoop(buttonLoop);
espurnaRegisterReload(_buttonConfigure);
}
void buttonLoop() {
// Sonoff Dual does not do real GPIO readings and we
// depend on the external MCU to send us relay / button events
// Lightfox uses the same protocol as Dual, but has slightly different actions
// TODO: move this to a separate 'hardware' setup file?
#if defined(ITEAD_SONOFF_DUAL)
if (Serial.available() >= 4) {
if (Serial.read() == 0xA0) {
if (Serial.read() == 0x04) {
unsigned char value = Serial.read();
if (Serial.read() == 0xA1) {
// RELAYs and BUTTONs are synchonized in the SIL F330
// The on-board BUTTON2 should toggle RELAY0 value
// Since we are not passing back RELAY2 value
// (in the relayStatus method) it will only be present
// here if it has actually been pressed
if ((value & 4) == 4) {
buttonEvent(2, BUTTON_EVENT_CLICK);
return;
}
// Otherwise check if any of the other two BUTTONs
// (in the header) has been pressed, but we should
// ensure that we only toggle one of them to avoid
// the synchronization going mad
// This loop is generic for any PSB-04 module
for (unsigned int i=0; i<relayCount(); i++) {
bool status = (value & (1 << i)) > 0;
// Check if the status for that relay has changed
if (relayStatus(i) != status) {
buttonEvent(i, BUTTON_EVENT_CLICK);
break;
}
}
}
}
}
}
void _buttonLoopSonoffDual() {
if (Serial.available() < 4) {
return;
}
unsigned char bytes[4] = {0};
Serial.readBytes(bytes, 4);
if ((bytes[0] != 0xA0) && (bytes[1] != 0x04) && (bytes[3] != 0xA1)) {
return;
}
#elif defined(FOXEL_LIGHTFOX_DUAL)
const unsigned char value [[gnu::unused]] = bytes[2];
if (Serial.available() >= 4) {
if (Serial.read() == 0xA0) {
if (Serial.read() == 0x04) {
unsigned char value = Serial.read();
if (Serial.read() == 0xA1) {
#if BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL
DEBUG_MSG_P(PSTR("[BUTTON] [LIGHTFOX] Received buttons mask: %d\n"), value);
// RELAYs and BUTTONs are synchonized in the SIL F330
// The on-board BUTTON2 should toggle RELAY0 value
// Since we are not passing back RELAY2 value
// (in the relayStatus method) it will only be present
// here if it has actually been pressed
if ((value & 4) == 4) {
buttonEvent(2, button_event_t::Click);
return;
}
for (unsigned int i=0; i<_buttons.size(); i++) {
// Otherwise check if any of the other two BUTTONs
// (in the header) has been pressed, but we should
// ensure that we only toggle one of them to avoid
// the synchronization going mad
// This loop is generic for any PSB-04 module
for (unsigned int i=0; i<relayCount(); i++) {
bool clicked = (value & (1 << i)) > 0;
const bool status = (value & (1 << i)) > 0;
if (clicked) {
buttonEvent(i, BUTTON_EVENT_CLICK);
}
}
}
}
}
// Check if the status for that relay has changed
if (relayStatus(i) != status) {
buttonEvent(i, button_event_t::Click);
break;
}
#else
}
for (size_t id = 0; id < _buttons.size(); ++id) {
auto& button = _buttons[id];
if (auto event = button.event->loop()) {
buttonEvent(id, _buttonMapEvent(
event,
button.event->getEventCount(),
button.event->getEventLength()
));
}
}
#elif BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL
DEBUG_MSG_P(PSTR("[BUTTON] [LIGHTFOX] Received buttons mask: %u\n"), value);
for (unsigned int i=0; i<_buttons.size(); i++) {
if ((value & (1 << i)) > 0);
buttonEvent(i, button_event_t::Click);
}
}
#endif // BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL
}
void _buttonLoopGeneric() {
for (size_t id = 0; id < _buttons.size(); ++id) {
auto event = _buttons[id].loop();
if (event != button_event_t::None) {
buttonEvent(id, event);
}
}
}
void buttonLoop() {
#if BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC
_buttonLoopGeneric();
#elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL)
_buttonLoopSonoffDual();
#else
#warning "Unknown value for BUTTON_EVENTS_SOURCE"
#endif
}


+ 102
- 44
code/espurna/button_config.h View File

@ -6,6 +6,18 @@ BUTTON MODULE
#pragma once
namespace ButtonMask {
enum {
Pushbutton = 1 << 0,
Switch = 1 << 1,
DefaultHigh = 1 << 2,
SetPullup = 1 << 3,
SetPulldown = 1 << 4
};
} // namespace ButtonMask
constexpr const unsigned char _buttonPin(unsigned char index) {
return (
(index == 0) ? BUTTON1_PIN :
@ -19,16 +31,16 @@ constexpr const unsigned char _buttonPin(unsigned char index) {
);
}
constexpr const unsigned char _buttonMode(unsigned char index) {
constexpr const unsigned char _buttonConfigBitmask(unsigned char index) {
return (
(index == 0) ? BUTTON1_MODE :
(index == 1) ? BUTTON2_MODE :
(index == 2) ? BUTTON3_MODE :
(index == 3) ? BUTTON4_MODE :
(index == 4) ? BUTTON5_MODE :
(index == 5) ? BUTTON6_MODE :
(index == 6) ? BUTTON7_MODE :
(index == 7) ? BUTTON8_MODE : (BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH)
(index == 0) ? (BUTTON1_CONFIG) :
(index == 1) ? (BUTTON2_CONFIG) :
(index == 2) ? (BUTTON3_CONFIG) :
(index == 3) ? (BUTTON4_CONFIG) :
(index == 4) ? (BUTTON5_CONFIG) :
(index == 5) ? (BUTTON6_CONFIG) :
(index == 6) ? (BUTTON7_CONFIG) :
(index == 7) ? (BUTTON8_CONFIG) : (BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH)
);
}
@ -41,7 +53,7 @@ constexpr const unsigned char _buttonPress(unsigned char index) {
(index == 4) ? BUTTON5_PRESS :
(index == 5) ? BUTTON6_PRESS :
(index == 6) ? BUTTON7_PRESS :
(index == 7) ? BUTTON8_PRESS : BUTTON_MODE_NONE
(index == 7) ? BUTTON8_PRESS : BUTTON_ACTION_NONE
);
}
@ -54,7 +66,7 @@ constexpr const unsigned char _buttonClick(unsigned char index) {
(index == 4) ? BUTTON5_CLICK :
(index == 5) ? BUTTON6_CLICK :
(index == 6) ? BUTTON7_CLICK :
(index == 7) ? BUTTON8_CLICK : BUTTON_MODE_NONE
(index == 7) ? BUTTON8_CLICK : BUTTON_ACTION_NONE
);
}
@ -67,7 +79,7 @@ constexpr const unsigned char _buttonDoubleClick(unsigned char index) {
(index == 4) ? BUTTON5_DBLCLICK :
(index == 5) ? BUTTON6_DBLCLICK :
(index == 6) ? BUTTON7_DBLCLICK :
(index == 7) ? BUTTON8_DBLCLICK : BUTTON_MODE_NONE
(index == 7) ? BUTTON8_DBLCLICK : BUTTON_ACTION_NONE
);
}
@ -80,7 +92,7 @@ constexpr const unsigned char _buttonTripleClick(unsigned char index) {
(index == 4) ? BUTTON5_TRIPLECLICK :
(index == 5) ? BUTTON6_TRIPLECLICK :
(index == 6) ? BUTTON7_TRIPLECLICK :
(index == 7) ? BUTTON8_TRIPLECLICK : BUTTON_MODE_NONE
(index == 7) ? BUTTON8_TRIPLECLICK : BUTTON_ACTION_NONE
);
}
@ -93,7 +105,7 @@ constexpr const unsigned char _buttonLongClick(unsigned char index) {
(index == 4) ? BUTTON5_LNGCLICK :
(index == 5) ? BUTTON6_LNGCLICK :
(index == 6) ? BUTTON7_LNGCLICK :
(index == 7) ? BUTTON8_LNGCLICK : BUTTON_MODE_NONE
(index == 7) ? BUTTON8_LNGCLICK : BUTTON_ACTION_NONE
);
}
@ -106,7 +118,7 @@ constexpr const unsigned char _buttonLongLongClick(unsigned char index) {
(index == 4) ? BUTTON5_LNGLNGCLICK :
(index == 5) ? BUTTON6_LNGLNGCLICK :
(index == 6) ? BUTTON7_LNGLNGCLICK :
(index == 7) ? BUTTON8_LNGLNGCLICK : BUTTON_MODE_NONE
(index == 7) ? BUTTON8_LNGLNGCLICK : BUTTON_ACTION_NONE
);
}
@ -123,50 +135,96 @@ constexpr const unsigned char _buttonRelay(unsigned char index) {
);
}
constexpr const unsigned char _buttonDecodeEventAction(unsigned long actions, unsigned char event) {
constexpr const unsigned long _buttonDebounceDelay() {
return BUTTON_DEBOUNCE_DELAY;
}
constexpr const unsigned long _buttonDebounceDelay(unsigned char index) {
return (
(event == BUTTON_EVENT_PRESSED) ? ((actions) & 0x0F) :
(event == BUTTON_EVENT_CLICK) ? ((actions >> 4) & 0x0F) :
(event == BUTTON_EVENT_DBLCLICK) ? ((actions >> 8) & 0x0F) :
(event == BUTTON_EVENT_LNGCLICK) ? ((actions >> 12) & 0x0F) :
(event == BUTTON_EVENT_LNGLNGCLICK) ? ((actions >> 16) & 0x0F) :
(event == BUTTON_EVENT_TRIPLECLICK) ? ((actions >> 20) & 0x0F) : BUTTON_MODE_NONE
(index == 0) ? BUTTON1_DEBOUNCE_DELAY :
(index == 1) ? BUTTON2_DEBOUNCE_DELAY :
(index == 2) ? BUTTON3_DEBOUNCE_DELAY :
(index == 3) ? BUTTON4_DEBOUNCE_DELAY :
(index == 4) ? BUTTON5_DEBOUNCE_DELAY :
(index == 5) ? BUTTON6_DEBOUNCE_DELAY :
(index == 6) ? BUTTON7_DEBOUNCE_DELAY :
(index == 7) ? BUTTON8_DEBOUNCE_DELAY : _buttonDebounceDelay()
);
}
constexpr const uint8_t _buttonMapReleased(uint8_t count, uint16_t length) {
constexpr const unsigned long _buttonRepeatDelay() {
return BUTTON_REPEAT_DELAY;
}
constexpr const unsigned long _buttonRepeatDelay(unsigned char index) {
return (
(1 == count) ? (
(length > BUTTON_LNGLNGCLICK_DELAY) ? BUTTON_EVENT_LNGLNGCLICK :
(length > BUTTON_LNGCLICK_DELAY) ? BUTTON_EVENT_LNGCLICK : BUTTON_EVENT_CLICK
) :
(2 == count) ? BUTTON_EVENT_DBLCLICK :
(3 == count) ? BUTTON_EVENT_TRIPLECLICK :
BUTTON_EVENT_NONE
(index == 0) ? BUTTON1_REPEAT_DELAY :
(index == 1) ? BUTTON2_REPEAT_DELAY :
(index == 2) ? BUTTON3_REPEAT_DELAY :
(index == 3) ? BUTTON4_REPEAT_DELAY :
(index == 4) ? BUTTON5_REPEAT_DELAY :
(index == 5) ? BUTTON6_REPEAT_DELAY :
(index == 6) ? BUTTON7_REPEAT_DELAY :
(index == 7) ? BUTTON8_REPEAT_DELAY : _buttonRepeatDelay()
);
}
constexpr const uint8_t _buttonMapEvent(uint8_t event, uint8_t count, uint16_t length) {
constexpr const unsigned long _buttonLongClickDelay() {
return BUTTON_LNGCLICK_DELAY;
}
constexpr const unsigned long _buttonLongClickDelay(unsigned char index) {
return (
(event == EVENT_PRESSED) ? BUTTON_EVENT_PRESSED :
(event == EVENT_CHANGED) ? BUTTON_EVENT_CLICK :
(event == EVENT_RELEASED) ? _buttonMapReleased(count, length) :
BUTTON_EVENT_NONE
(index == 0) ? BUTTON1_LNGCLICK_DELAY :
(index == 1) ? BUTTON2_LNGCLICK_DELAY :
(index == 2) ? BUTTON3_LNGCLICK_DELAY :
(index == 3) ? BUTTON4_LNGCLICK_DELAY :
(index == 4) ? BUTTON5_LNGCLICK_DELAY :
(index == 5) ? BUTTON6_LNGCLICK_DELAY :
(index == 6) ? BUTTON7_LNGCLICK_DELAY :
(index == 7) ? BUTTON8_LNGCLICK_DELAY : _buttonLongClickDelay()
);
}
constexpr uint32_t _buttonConstructActions(unsigned long pressed, unsigned long click, unsigned long dblclick, unsigned long lngclick, unsigned long lnglngclick, unsigned long tripleclick) {
constexpr const unsigned long _buttonLongLongClickDelay() {
return BUTTON_LNGLNGCLICK_DELAY;
}
constexpr const unsigned long _buttonLongLongClickDelay(unsigned char index) {
return (
(tripleclick << 20) |
(lnglngclick << 16) |
(lngclick << 12) |
(dblclick << 8) |
(click << 4) |
pressed
(index == 0) ? BUTTON1_LNGLNGCLICK_DELAY :
(index == 1) ? BUTTON2_LNGLNGCLICK_DELAY :
(index == 2) ? BUTTON3_LNGLNGCLICK_DELAY :
(index == 3) ? BUTTON4_LNGLNGCLICK_DELAY :
(index == 4) ? BUTTON5_LNGLNGCLICK_DELAY :
(index == 5) ? BUTTON6_LNGLNGCLICK_DELAY :
(index == 6) ? BUTTON7_LNGLNGCLICK_DELAY :
(index == 7) ? BUTTON8_LNGLNGCLICK_DELAY : _buttonLongLongClickDelay()
);
}
constexpr uint32_t _buttonConstructActions(unsigned char id) {
return _buttonConstructActions(_buttonPress(id), _buttonClick(id), _buttonDoubleClick(id), _buttonLongClick(id), _buttonLongLongClick(id), _buttonTripleClick(id));
constexpr const bool _buttonMqttSendAllEvents(unsigned char index) {
return (
(index == 0) ? (1 == BUTTON1_MQTT_SEND_ALL_EVENTS) :
(index == 1) ? (1 == BUTTON2_MQTT_SEND_ALL_EVENTS) :
(index == 2) ? (1 == BUTTON3_MQTT_SEND_ALL_EVENTS) :
(index == 3) ? (1 == BUTTON4_MQTT_SEND_ALL_EVENTS) :
(index == 4) ? (1 == BUTTON5_MQTT_SEND_ALL_EVENTS) :
(index == 5) ? (1 == BUTTON6_MQTT_SEND_ALL_EVENTS) :
(index == 6) ? (1 == BUTTON7_MQTT_SEND_ALL_EVENTS) :
(index == 7) ? (1 == BUTTON8_MQTT_SEND_ALL_EVENTS) : (1 == BUTTON_MQTT_SEND_ALL_EVENTS)
);
}
constexpr const bool _buttonMqttRetain(unsigned char index) {
return (
(index == 0) ? (1 == BUTTON1_MQTT_RETAIN) :
(index == 1) ? (1 == BUTTON2_MQTT_RETAIN) :
(index == 2) ? (1 == BUTTON3_MQTT_RETAIN) :
(index == 3) ? (1 == BUTTON4_MQTT_RETAIN) :
(index == 4) ? (1 == BUTTON5_MQTT_RETAIN) :
(index == 5) ? (1 == BUTTON6_MQTT_RETAIN) :
(index == 6) ? (1 == BUTTON7_MQTT_RETAIN) :
(index == 7) ? (1 == BUTTON8_MQTT_RETAIN) : (1 == BUTTON_MQTT_RETAIN)
);
}

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

@ -29,14 +29,14 @@
#include "custom.h"
#endif
#include "buildtime.h"
#include "version.h"
#include "types.h"
#include "arduino.h"
#include "hardware.h"
#include "general.h"
#include "defaults.h"
#include "buildtime.h"
#include "deprecated.h"
#include "general.h"
#include "dependencies.h"
#include "sensors.h"
#include "webui.h"

+ 228
- 64
code/espurna/config/defaults.h View File

@ -33,179 +33,179 @@
#define BUTTON8_PIN GPIO_NONE
#endif
#ifndef BUTTON1_MODE
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON1_CONFIG
#define BUTTON1_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON2_MODE
#define BUTTON2_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON2_CONFIG
#define BUTTON2_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON3_MODE
#define BUTTON3_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON3_CONFIG
#define BUTTON3_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON4_MODE
#define BUTTON4_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON4_CONFIG
#define BUTTON4_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON5_MODE
#define BUTTON5_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON5_CONFIG
#define BUTTON5_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON6_MODE
#define BUTTON6_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON6_CONFIG
#define BUTTON6_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON7_MODE
#define BUTTON7_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON7_CONFIG
#define BUTTON7_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON8_MODE
#define BUTTON8_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#ifndef BUTTON8_CONFIG
#define BUTTON8_CONFIG BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
#endif
#ifndef BUTTON1_PRESS
#define BUTTON1_PRESS BUTTON_MODE_NONE
#define BUTTON1_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON2_PRESS
#define BUTTON2_PRESS BUTTON_MODE_NONE
#define BUTTON2_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON3_PRESS
#define BUTTON3_PRESS BUTTON_MODE_NONE
#define BUTTON3_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON4_PRESS
#define BUTTON4_PRESS BUTTON_MODE_NONE
#define BUTTON4_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON5_PRESS
#define BUTTON5_PRESS BUTTON_MODE_NONE
#define BUTTON5_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON6_PRESS
#define BUTTON6_PRESS BUTTON_MODE_NONE
#define BUTTON6_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON7_PRESS
#define BUTTON7_PRESS BUTTON_MODE_NONE
#define BUTTON7_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON8_PRESS
#define BUTTON8_PRESS BUTTON_MODE_NONE
#define BUTTON8_PRESS BUTTON_ACTION_NONE
#endif
#ifndef BUTTON1_CLICK
#define BUTTON1_CLICK BUTTON_MODE_TOGGLE
#define BUTTON1_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON2_CLICK
#define BUTTON2_CLICK BUTTON_MODE_TOGGLE
#define BUTTON2_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON3_CLICK
#define BUTTON3_CLICK BUTTON_MODE_TOGGLE
#define BUTTON3_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON4_CLICK
#define BUTTON4_CLICK BUTTON_MODE_TOGGLE
#define BUTTON4_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON5_CLICK
#define BUTTON5_CLICK BUTTON_MODE_TOGGLE
#define BUTTON5_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON6_CLICK
#define BUTTON6_CLICK BUTTON_MODE_TOGGLE
#define BUTTON6_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON7_CLICK
#define BUTTON7_CLICK BUTTON_MODE_TOGGLE
#define BUTTON7_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON8_CLICK
#define BUTTON8_CLICK BUTTON_MODE_TOGGLE
#define BUTTON8_CLICK BUTTON_ACTION_TOGGLE
#endif
#ifndef BUTTON1_DBLCLICK
#define BUTTON1_DBLCLICK BUTTON_MODE_AP
#define BUTTON1_DBLCLICK BUTTON_ACTION_AP
#endif
#ifndef BUTTON2_DBLCLICK
#define BUTTON2_DBLCLICK BUTTON_MODE_NONE
#define BUTTON2_DBLCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON3_DBLCLICK
#define BUTTON3_DBLCLICK BUTTON_MODE_NONE
#define BUTTON3_DBLCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON4_DBLCLICK
#define BUTTON4_DBLCLICK BUTTON_MODE_NONE
#define BUTTON4_DBLCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON5_DBLCLICK
#define BUTTON5_DBLCLICK BUTTON_MODE_NONE
#define BUTTON5_DBLCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON6_DBLCLICK
#define BUTTON6_DBLCLICK BUTTON_MODE_NONE
#define BUTTON6_DBLCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON7_DBLCLICK
#define BUTTON7_DBLCLICK BUTTON_MODE_NONE
#define BUTTON7_DBLCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON8_DBLCLICK
#define BUTTON8_DBLCLICK BUTTON_MODE_NONE
#define BUTTON8_DBLCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON1_TRIPLECLICK
#define BUTTON1_TRIPLECLICK BUTTON_MODE_SMART_CONFIG
#define BUTTON1_TRIPLECLICK BUTTON_ACTION_SMART_CONFIG
#endif
#ifndef BUTTON2_TRIPLECLICK
#define BUTTON2_TRIPLECLICK BUTTON_MODE_NONE
#define BUTTON2_TRIPLECLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON3_TRIPLECLICK
#define BUTTON3_TRIPLECLICK BUTTON_MODE_NONE
#define BUTTON3_TRIPLECLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON4_TRIPLECLICK
#define BUTTON4_TRIPLECLICK BUTTON_MODE_NONE
#define BUTTON4_TRIPLECLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON5_TRIPLECLICK
#define BUTTON5_TRIPLECLICK BUTTON_MODE_NONE
#define BUTTON5_TRIPLECLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON6_TRIPLECLICK
#define BUTTON6_TRIPLECLICK BUTTON_MODE_NONE
#define BUTTON6_TRIPLECLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON7_TRIPLECLICK
#define BUTTON7_TRIPLECLICK BUTTON_MODE_NONE
#define BUTTON7_TRIPLECLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON8_TRIPLECLICK
#define BUTTON8_TRIPLECLICK BUTTON_MODE_NONE
#define BUTTON8_TRIPLECLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON1_LNGCLICK
#define BUTTON1_LNGCLICK BUTTON_MODE_RESET
#define BUTTON1_LNGCLICK BUTTON_ACTION_RESET
#endif
#ifndef BUTTON2_LNGCLICK
#define BUTTON2_LNGCLICK BUTTON_MODE_NONE
#define BUTTON2_LNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON3_LNGCLICK
#define BUTTON3_LNGCLICK BUTTON_MODE_NONE
#define BUTTON3_LNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON4_LNGCLICK
#define BUTTON4_LNGCLICK BUTTON_MODE_NONE
#define BUTTON4_LNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON5_LNGCLICK
#define BUTTON5_LNGCLICK BUTTON_MODE_NONE
#define BUTTON5_LNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON6_LNGCLICK
#define BUTTON6_LNGCLICK BUTTON_MODE_NONE
#define BUTTON6_LNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON7_LNGCLICK
#define BUTTON7_LNGCLICK BUTTON_MODE_NONE
#define BUTTON7_LNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON8_LNGCLICK
#define BUTTON8_LNGCLICK BUTTON_MODE_NONE
#define BUTTON8_LNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON1_LNGLNGCLICK
#define BUTTON1_LNGLNGCLICK BUTTON_MODE_FACTORY
#define BUTTON1_LNGLNGCLICK BUTTON_ACTION_FACTORY
#endif
#ifndef BUTTON2_LNGLNGCLICK
#define BUTTON2_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON2_LNGLNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON3_LNGLNGCLICK
#define BUTTON3_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON3_LNGLNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON4_LNGLNGCLICK
#define BUTTON4_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON4_LNGLNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON5_LNGLNGCLICK
#define BUTTON5_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON5_LNGLNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON6_LNGLNGCLICK
#define BUTTON6_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON6_LNGLNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON7_LNGLNGCLICK
#define BUTTON7_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON7_LNGLNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON8_LNGLNGCLICK
#define BUTTON8_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON8_LNGLNGCLICK BUTTON_ACTION_NONE
#endif
#ifndef BUTTON1_RELAY
@ -233,6 +233,170 @@
#define BUTTON8_RELAY RELAY_NONE
#endif
#ifndef BUTTON1_DEBOUNCE_DELAY
#define BUTTON1_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON2_DEBOUNCE_DELAY
#define BUTTON2_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON3_DEBOUNCE_DELAY
#define BUTTON3_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON4_DEBOUNCE_DELAY
#define BUTTON4_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON5_DEBOUNCE_DELAY
#define BUTTON5_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON6_DEBOUNCE_DELAY
#define BUTTON6_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON7_DEBOUNCE_DELAY
#define BUTTON7_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON8_DEBOUNCE_DELAY
#define BUTTON8_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY
#endif
#ifndef BUTTON1_REPEAT_DELAY
#define BUTTON1_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON2_REPEAT_DELAY
#define BUTTON2_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON3_REPEAT_DELAY
#define BUTTON3_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON4_REPEAT_DELAY
#define BUTTON4_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON5_REPEAT_DELAY
#define BUTTON5_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON6_REPEAT_DELAY
#define BUTTON6_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON7_REPEAT_DELAY
#define BUTTON7_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON8_REPEAT_DELAY
#define BUTTON8_REPEAT_DELAY BUTTON_REPEAT_DELAY
#endif
#ifndef BUTTON1_LNGCLICK_DELAY
#define BUTTON1_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON2_LNGCLICK_DELAY
#define BUTTON2_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON3_LNGCLICK_DELAY
#define BUTTON3_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON4_LNGCLICK_DELAY
#define BUTTON4_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON5_LNGCLICK_DELAY
#define BUTTON5_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON6_LNGCLICK_DELAY
#define BUTTON6_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON7_LNGCLICK_DELAY
#define BUTTON7_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON8_LNGCLICK_DELAY
#define BUTTON8_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY
#endif
#ifndef BUTTON1_LNGLNGCLICK_DELAY
#define BUTTON1_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON2_LNGLNGCLICK_DELAY
#define BUTTON2_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON3_LNGLNGCLICK_DELAY
#define BUTTON3_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON4_LNGLNGCLICK_DELAY
#define BUTTON4_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON5_LNGLNGCLICK_DELAY
#define BUTTON5_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON6_LNGLNGCLICK_DELAY
#define BUTTON6_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON7_LNGLNGCLICK_DELAY
#define BUTTON7_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON8_LNGLNGCLICK_DELAY
#define BUTTON8_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY
#endif
#ifndef BUTTON1_MQTT_SEND_ALL_EVENTS
#define BUTTON1_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON2_MQTT_SEND_ALL_EVENTS
#define BUTTON2_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON3_MQTT_SEND_ALL_EVENTS
#define BUTTON3_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON4_MQTT_SEND_ALL_EVENTS
#define BUTTON4_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON5_MQTT_SEND_ALL_EVENTS
#define BUTTON5_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON6_MQTT_SEND_ALL_EVENTS
#define BUTTON6_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON7_MQTT_SEND_ALL_EVENTS
#define BUTTON7_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON8_MQTT_SEND_ALL_EVENTS
#define BUTTON8_MQTT_SEND_ALL_EVENTS BUTTON_MQTT_SEND_ALL_EVENTS
#endif
#ifndef BUTTON1_MQTT_RETAIN
#define BUTTON1_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
#ifndef BUTTON2_MQTT_RETAIN
#define BUTTON2_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
#ifndef BUTTON3_MQTT_RETAIN
#define BUTTON3_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
#ifndef BUTTON4_MQTT_RETAIN
#define BUTTON4_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
#ifndef BUTTON5_MQTT_RETAIN
#define BUTTON5_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
#ifndef BUTTON6_MQTT_RETAIN
#define BUTTON6_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
#ifndef BUTTON7_MQTT_RETAIN
#define BUTTON7_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
#ifndef BUTTON8_MQTT_RETAIN
#define BUTTON8_MQTT_RETAIN BUTTON_MQTT_RETAIN
#endif
// -----------------------------------------------------------------------------
// Encoders
// -----------------------------------------------------------------------------


+ 15
- 2
code/espurna/config/dependencies.h View File

@ -157,12 +157,25 @@
#define NTP_LEGACY_SUPPORT 0
#endif
//------------------------------------------------------------------------------
// When using Dual / Lightfox Dual, notify that Serial should be used
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL)
#if DEBUG_SERIAL_SUPPORT
#warning "DEBUG_SERIAL_SUPPORT conflicts with the current BUTTON_EVENTS_SOURCE"
#undef DEBUG_SERIAL_SUPPORT
#define DEBUG_SERIAL_SUPPORT 0
#endif
#endif
//------------------------------------------------------------------------------
// It looks more natural that one click will enable display
// and long click will switch relay
#if THERMOSTAT_DISPLAY_SUPPORT
#undef BUTTON1_CLICK
#define BUTTON1_CLICK BUTTON_MODE_DISPLAY_ON
#define BUTTON1_CLICK BUTTON_ACTION_DISPLAY_ON
#undef BUTTON1_LNGCLICK
#define BUTTON1_LNGCLICK BUTTON_MODE_TOGGLE
#define BUTTON1_LNGCLICK BUTTON_ACTION_TOGGLE
#endif

+ 50
- 0
code/espurna/config/deprecated.h View File

@ -48,3 +48,53 @@
#warning "Current implementation of AsyncMqttClient with axTLS is no longer supported. Consider switching to the SECURE_CLIENT configuration with MQTT_LIBRARY_ARDUINOMQTT or MQTT_LIBRARY_PUBSUBCLIENT. See: https://github.com/xoseperez/espurna/issues/1465"
#endif
// 1.14.2 changes preprocessor var name
#ifdef BUTTON_DBLCLICK_DELAY
#warning "BUTTON_DBLCLICK_DELAY is deprecated! Please use BUTTON_REPEAT_DELAY instead"
#define BUTTON_REPEAT_DELAY BUTTON_DBLCLICK_DELAY
#endif
#ifdef BUTTON1_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON1_CONFIG BUTTON1_MODE
#endif
#ifdef BUTTON2_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON2_CONFIG BUTTON2_MODE
#endif
#ifdef BUTTON3_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON3_CONFIG BUTTON3_MODE
#endif
#ifdef BUTTON4_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON4_CONFIG BUTTON4_MODE
#endif
#ifdef BUTTON4_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON4_CONFIG BUTTON4_MODE
#endif
#ifdef BUTTON5_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON5_CONFIG BUTTON5_MODE
#endif
#ifdef BUTTON6_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON6_CONFIG BUTTON6_MODE
#endif
#ifdef BUTTON7_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON7_CONFIG BUTTON7_MODE
#endif
#ifdef BUTTON8_MODE
#warning "BUTTON[1-8]_MODE is deprecated! Please use BUTTON[1-8]_CONFIG instead"
#define BUTTON8_CONFIG BUTTON8_MODE
#endif

+ 15
- 4
code/espurna/config/general.h View File

@ -374,8 +374,8 @@
#define BUTTON_DEBOUNCE_DELAY 50 // Debounce delay (ms)
#endif
#ifndef BUTTON_DBLCLICK_DELAY
#define BUTTON_DBLCLICK_DELAY 500 // Time in ms to wait for a second (or third...) click
#ifndef BUTTON_REPEAT_DELAY
#define BUTTON_REPEAT_DELAY 500 // Time in ms to wait for a second (or third...) click
#endif
#ifndef BUTTON_LNGCLICK_DELAY
@ -387,8 +387,19 @@
#endif
#ifndef BUTTON_MQTT_SEND_ALL_EVENTS
#define BUTTON_MQTT_SEND_ALL_EVENTS 0 // 0 - to send only events the are bound to actions
// 1 - to send all button events to MQTT
#define BUTTON_MQTT_SEND_ALL_EVENTS 0 // 0 - to send only events the are bound to actions
// 1 - to send all button events to MQTT
#endif
#ifndef BUTTON_MQTT_RETAIN
#define BUTTON_MQTT_RETAIN 0
#endif
#ifndef BUTTON_EVENTS_SOURCE
#define BUTTON_EVENTS_SOURCE BUTTON_EVENTS_SOURCE_GENERIC // Type of button event source. One of:
// BUTTON_EVENTS_SOURCE_GENERIC - GPIOs (virtual or real)
// BUTTON_EVENTS_SOURCE_SONOFF_DUAL - hardware specific, drive buttons through serial connection
// BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL - similar to Itead Sonoff Dual, hardware specific
#endif
//------------------------------------------------------------------------------


+ 291
- 279
code/espurna/config/hardware.h
File diff suppressed because it is too large
View File


+ 57
- 39
code/espurna/config/types.h View File

@ -22,37 +22,48 @@
// BUTTONS
//------------------------------------------------------------------------------
#define BUTTON_EVENT_NONE 0
#define BUTTON_EVENT_PRESSED 1
#define BUTTON_EVENT_RELEASED 2
#define BUTTON_EVENT_CLICK 2
#define BUTTON_EVENT_DBLCLICK 3
#define BUTTON_EVENT_LNGCLICK 4
#define BUTTON_EVENT_LNGLNGCLICK 5
#define BUTTON_EVENT_TRIPLECLICK 6
#define BUTTON_MODE_NONE 0
#define BUTTON_MODE_TOGGLE 1
#define BUTTON_MODE_ON 2
#define BUTTON_MODE_OFF 3
#define BUTTON_MODE_AP 4
#define BUTTON_MODE_RESET 5
#define BUTTON_MODE_PULSE 6
#define BUTTON_MODE_FACTORY 7
#define BUTTON_MODE_WPS 8
#define BUTTON_MODE_SMART_CONFIG 9
#define BUTTON_MODE_DIM_UP 10
#define BUTTON_MODE_DIM_DOWN 11
#define BUTTON_MODE_DISPLAY_ON 12
// Needed for ESP8285 boards under Windows using PlatformIO (?)
#ifndef BUTTON_PUSHBUTTON
#define BUTTON_PUSHBUTTON 0
#define BUTTON_SWITCH 1
#define BUTTON_DEFAULT_HIGH 2
#define BUTTON_SET_PULLUP 4
#endif
// button actions, limited to 4-bit number (0b1111 / 0xf / 15)
#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 15u
// Deprecated: legacy mapping, changed to action from above
#define BUTTON_MODE_NONE BUTTON_ACTION_NONE
#define BUTTON_MODE_TOGGLE BUTTON_ACTION_TOGGLE
#define BUTTON_MODE_ON BUTTON_ACTION_ON
#define BUTTON_MODE_OFF BUTTON_ACTION_OFF
#define BUTTON_MODE_AP BUTTON_ACTION_AP
#define BUTTON_MODE_RESET BUTTON_ACTION_RESET
#define BUTTON_MODE_PULSE BUTTON_ACTION_PULSE
#define BUTTON_MODE_FACTORY BUTTON_ACTION_FACTORY
#define BUTTON_MODE_WPS BUTTON_ACTION_WPS
#define BUTTON_MODE_SMART_CONFIG BUTTON_ACTION_SMART_CONFIG
#define BUTTON_MODE_DIM_UP BUTTON_ACTION_DIM_UP
#define BUTTON_MODE_DIM_DOWN BUTTON_ACTION_DIM_DOWN
#define BUTTON_MODE_DISPLAY_ON BUTTON_ACTION_DISPLAY_ON
// compat definitions for DebounceEvent
#define BUTTON_PUSHBUTTON ButtonMask::Pushbutton
#define BUTTON_SWITCH ButtonMask::Switch
#define BUTTON_DEFAULT_HIGH ButtonMask::DefaultHigh
#define BUTTON_SET_PULLUP ButtonMask::SetPullup
#define BUTTON_SET_PULLDOWN ButtonMask::SetPulldown
// configure which type of event emitter is used
#define BUTTON_EVENTS_SOURCE_GENERIC 0
#define BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL 1
#define BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL 2
//------------------------------------------------------------------------------
// ENCODER
@ -199,14 +210,21 @@
// IR
// -----------------------------------------------------------------------------
// IR Button modes
#define IR_BUTTON_MODE_NONE 0
#define IR_BUTTON_MODE_RGB 1
#define IR_BUTTON_MODE_HSV 2
#define IR_BUTTON_MODE_BRIGHTER 3
#define IR_BUTTON_MODE_STATE 4
#define IR_BUTTON_MODE_EFFECT 5
#define IR_BUTTON_MODE_TOGGLE 6
#define IR_BUTTON_ACTION_NONE 0
#define IR_BUTTON_ACTION_RGB 1
#define IR_BUTTON_ACTION_HSV 2
#define IR_BUTTON_ACTION_BRIGHTER 3
#define IR_BUTTON_ACTION_STATE 4
#define IR_BUTTON_ACTION_EFFECT 5
#define IR_BUTTON_ACTION_TOGGLE 6
#define IR_BUTTON_MODE_NONE IR_BUTTON_ACTION_NONE
#define IR_BUTTON_MODE_RGB IR_BUTTON_ACTION_RGB
#define IR_BUTTON_MODE_HSV IR_BUTTON_ACTION_HSV
#define IR_BUTTON_MODE_BRIGHTER IR_BUTTON_ACTION_BRIGHTER
#define IR_BUTTON_MODE_STATE IR_BUTTON_ACTION_STATE
#define IR_BUTTON_MODE_EFFECT IR_BUTTON_ACTION_EFFECT
#define IR_BUTTON_MODE_TOGGLE IR_BUTTON_ACTION_TOGGLE
#define LIGHT_EFFECT_SOLID 0
#define LIGHT_EFFECT_FLASH 1


BIN
code/espurna/data/index.all.html.gz View File


BIN
code/espurna/data/index.light.html.gz View File


BIN
code/espurna/data/index.lightfox.html.gz View File


BIN
code/espurna/data/index.rfbridge.html.gz View File


BIN
code/espurna/data/index.rfm69.html.gz View File


BIN
code/espurna/data/index.sensor.html.gz View File


BIN
code/espurna/data/index.small.html.gz View File


BIN
code/espurna/data/index.thermostat.html.gz View File


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

@ -8,6 +8,19 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#pragma once
#include "libs/BasePin.h"
// real hardware pin
class GpioPin final : virtual public BasePin {
public:
GpioPin(unsigned char pin);
void pinMode(int8_t mode);
void digitalWrite(int8_t val);
int digitalRead();
};
bool gpioValid(unsigned char gpio);
bool gpioGetLock(unsigned char gpio);
bool gpioReleaseLock(unsigned char gpio);


+ 20
- 0
code/espurna/gpio.ino View File

@ -10,6 +10,26 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <bitset>
// We need to explicitly call the constructor, because we need to set the const `pin`:
// https://isocpp.org/wiki/faq/multiple-inheritance#virtual-inheritance-ctors
GpioPin::GpioPin(unsigned char pin) :
BasePin(pin)
{}
inline void GpioPin::pinMode(int8_t mode) {
::pinMode(this->pin, mode);
}
inline void GpioPin::digitalWrite(int8_t val) {
::digitalWrite(this->pin, val);
}
inline int GpioPin::digitalRead() {
return ::digitalRead(this->pin);
}
// --------------------------------------------------------------------------
constexpr const size_t GPIO_PINS = 17;
std::bitset<GPIO_PINS> _gpio_locked;


+ 28
- 26
code/espurna/ir.ino View File

@ -280,45 +280,47 @@ void _irProcess(unsigned char type, unsigned long code) {
uint32_t button_code = pgm_read_dword(&IR_BUTTON[i][0]);
if (code == button_code) {
unsigned long button_mode = pgm_read_dword(&IR_BUTTON[i][1]);
unsigned long button_action = pgm_read_dword(&IR_BUTTON[i][1]);
unsigned long button_value = pgm_read_dword(&IR_BUTTON[i][2]);
if (button_mode == IR_BUTTON_MODE_STATE) {
relayStatus(0, button_value);
}
switch (button_action) {
case IR_BUTTON_ACTION_STATE:
relayStatus(0, button_value);
break;
if (button_mode == IR_BUTTON_MODE_TOGGLE) {
relayToggle(button_value);
}
case IR_BUTTON_ACTION_TOGGLE:
relayToggle(button_value);
break;
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
if (button_mode == IR_BUTTON_MODE_BRIGHTER) {
case IR_BUTTON_ACTION_BRIGHTER:
lightBrightnessStep(button_value ? 1 : -1);
lightUpdate(true, true);
nice_delay(150); //debounce
}
break;
if (button_mode == IR_BUTTON_MODE_RGB) {
case IR_BUTTON_ACTION_RGB:
lightColor(button_value);
}
/*
#if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
if (button_mode == IR_BUTTON_MODE_EFFECT) {
_buttonAnimMode(button_value);
}
#endif
*/
lightUpdate(true, true);
break;
/*
#if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
case IR_BUTTON_ACTION_EFFECT:
_buttonAnimMode(button_value);
break;
#endif
*/
/*
if (button_mode == IR_BUTTON_MODE_HSV) {
/*
case IR_BUTTON_ACTION_HSV:
lightColor(button_value);
}
*/
lightUpdate(true, true);
break;
}
*/
#endif
#endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
found = true;
break;


+ 93
- 93
code/espurna/ir_button.h View File

@ -33,35 +33,35 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
const uint32_t IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xFF906F, IR_BUTTON_MODE_BRIGHTER, 1 },
{ 0xFFB847, IR_BUTTON_MODE_BRIGHTER, 0 },
{ 0xFFF807, IR_BUTTON_MODE_STATE, 0 },
{ 0xFFB04F, IR_BUTTON_MODE_STATE, 1 },
{ 0xFF9867, IR_BUTTON_MODE_RGB, 0xFF0000 },
{ 0xFFD827, IR_BUTTON_MODE_RGB, 0x00FF00 },
{ 0xFF8877, IR_BUTTON_MODE_RGB, 0x0000FF },
{ 0xFFA857, IR_BUTTON_MODE_RGB, 0xFFFFFF },
{ 0xFFE817, IR_BUTTON_MODE_RGB, 0xD13A01 },
{ 0xFF48B7, IR_BUTTON_MODE_RGB, 0x00E644 },
{ 0xFF6897, IR_BUTTON_MODE_RGB, 0x0040A7 },
{ 0xFFB24D, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xFF02FD, IR_BUTTON_MODE_RGB, 0xE96F2A },
{ 0xFF32CD, IR_BUTTON_MODE_RGB, 0x00BEBF },
{ 0xFF20DF, IR_BUTTON_MODE_RGB, 0x56406F },
{ 0xFF00FF, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xFF50AF, IR_BUTTON_MODE_RGB, 0xEE9819 },
{ 0xFF7887, IR_BUTTON_MODE_RGB, 0x00799A },
{ 0xFF708F, IR_BUTTON_MODE_RGB, 0x944E80 },
{ 0xFF58A7, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FADE },
{ 0xFF38C7, IR_BUTTON_MODE_RGB, 0xFFFF00 },
{ 0xFF28D7, IR_BUTTON_MODE_RGB, 0x0060A1 },
{ 0xFFF00F, IR_BUTTON_MODE_RGB, 0xEF45AD },
{ 0xFF30CF, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_SMOOTH }
{ 0xFF906F, IR_BUTTON_ACTION_BRIGHTER, 1 },
{ 0xFFB847, IR_BUTTON_ACTION_BRIGHTER, 0 },
{ 0xFFF807, IR_BUTTON_ACTION_STATE, 0 },
{ 0xFFB04F, IR_BUTTON_ACTION_STATE, 1 },
{ 0xFF9867, IR_BUTTON_ACTION_RGB, 0xFF0000 },
{ 0xFFD827, IR_BUTTON_ACTION_RGB, 0x00FF00 },
{ 0xFF8877, IR_BUTTON_ACTION_RGB, 0x0000FF },
{ 0xFFA857, IR_BUTTON_ACTION_RGB, 0xFFFFFF },
{ 0xFFE817, IR_BUTTON_ACTION_RGB, 0xD13A01 },
{ 0xFF48B7, IR_BUTTON_ACTION_RGB, 0x00E644 },
{ 0xFF6897, IR_BUTTON_ACTION_RGB, 0x0040A7 },
{ 0xFFB24D, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xFF02FD, IR_BUTTON_ACTION_RGB, 0xE96F2A },
{ 0xFF32CD, IR_BUTTON_ACTION_RGB, 0x00BEBF },
{ 0xFF20DF, IR_BUTTON_ACTION_RGB, 0x56406F },
{ 0xFF00FF, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xFF50AF, IR_BUTTON_ACTION_RGB, 0xEE9819 },
{ 0xFF7887, IR_BUTTON_ACTION_RGB, 0x00799A },
{ 0xFF708F, IR_BUTTON_ACTION_RGB, 0x944E80 },
{ 0xFF58A7, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_FADE },
{ 0xFF38C7, IR_BUTTON_ACTION_RGB, 0xFFFF00 },
{ 0xFF28D7, IR_BUTTON_ACTION_RGB, 0x0060A1 },
{ 0xFFF00F, IR_BUTTON_ACTION_RGB, 0xEF45AD },
{ 0xFF30CF, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_SMOOTH }
};
@ -90,35 +90,35 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xFF00FF, IR_BUTTON_MODE_BRIGHTER, 1 },
{ 0xFF807F, IR_BUTTON_MODE_BRIGHTER, 0 },
{ 0xFF40BF, IR_BUTTON_MODE_STATE, 0 },
{ 0xFFC03F, IR_BUTTON_MODE_STATE, 1 },
{ 0xFF00FF, IR_BUTTON_ACTION_BRIGHTER, 1 },
{ 0xFF807F, IR_BUTTON_ACTION_BRIGHTER, 0 },
{ 0xFF40BF, IR_BUTTON_ACTION_STATE, 0 },
{ 0xFFC03F, IR_BUTTON_ACTION_STATE, 1 },
{ 0xFF20DF, IR_BUTTON_MODE_RGB, 0xFF0000 },
{ 0xFFA05F, IR_BUTTON_MODE_RGB, 0x00FF00 },
{ 0xFF609F, IR_BUTTON_MODE_RGB, 0x0000FF },
{ 0xFFE01F, IR_BUTTON_MODE_RGB, 0xFFFFFF },
{ 0xFF20DF, IR_BUTTON_ACTION_RGB, 0xFF0000 },
{ 0xFFA05F, IR_BUTTON_ACTION_RGB, 0x00FF00 },
{ 0xFF609F, IR_BUTTON_ACTION_RGB, 0x0000FF },
{ 0xFFE01F, IR_BUTTON_ACTION_RGB, 0xFFFFFF },
{ 0xFF10EF, IR_BUTTON_MODE_RGB, 0xD13A01 },
{ 0xFF906F, IR_BUTTON_MODE_RGB, 0x00E644 },
{ 0xFF50AF, IR_BUTTON_MODE_RGB, 0x0040A7 },
{ 0xFFD02F, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xFF10EF, IR_BUTTON_ACTION_RGB, 0xD13A01 },
{ 0xFF906F, IR_BUTTON_ACTION_RGB, 0x00E644 },
{ 0xFF50AF, IR_BUTTON_ACTION_RGB, 0x0040A7 },
{ 0xFFD02F, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xFF30CF, IR_BUTTON_MODE_RGB, 0xE96F2A },
{ 0xFFB04F, IR_BUTTON_MODE_RGB, 0x00BEBF },
{ 0xFF708F, IR_BUTTON_MODE_RGB, 0x56406F },
{ 0xFFF00F, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xFF30CF, IR_BUTTON_ACTION_RGB, 0xE96F2A },
{ 0xFFB04F, IR_BUTTON_ACTION_RGB, 0x00BEBF },
{ 0xFF708F, IR_BUTTON_ACTION_RGB, 0x56406F },
{ 0xFFF00F, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xFF08F7, IR_BUTTON_MODE_RGB, 0xEE9819 },
{ 0xFF8877, IR_BUTTON_MODE_RGB, 0x00799A },
{ 0xFF48B7, IR_BUTTON_MODE_RGB, 0x944E80 },
{ 0xFFC837, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FADE },
{ 0xFF08F7, IR_BUTTON_ACTION_RGB, 0xEE9819 },
{ 0xFF8877, IR_BUTTON_ACTION_RGB, 0x00799A },
{ 0xFF48B7, IR_BUTTON_ACTION_RGB, 0x944E80 },
{ 0xFFC837, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_FADE },
{ 0xFF28D7, IR_BUTTON_MODE_RGB, 0xFFFF00 },
{ 0xFFA857, IR_BUTTON_MODE_RGB, 0x0060A1 },
{ 0xFF6897, IR_BUTTON_MODE_RGB, 0xEF45AD },
{ 0xFFE817, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_SMOOTH }
{ 0xFF28D7, IR_BUTTON_ACTION_RGB, 0xFFFF00 },
{ 0xFFA857, IR_BUTTON_ACTION_RGB, 0x0060A1 },
{ 0xFF6897, IR_BUTTON_ACTION_RGB, 0xEF45AD },
{ 0xFFE817, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_SMOOTH }
};
@ -141,19 +141,19 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xE0E020DF, IR_BUTTON_MODE_TOGGLE, 0 }, // Toggle Relay #0
{ 0xE0E0A05F, IR_BUTTON_MODE_TOGGLE, 1 }, // Toggle Relay #1
{ 0xE0E0609F, IR_BUTTON_MODE_TOGGLE, 2 }, // Toggle Relay #2
{ 0xE0E020DF, IR_BUTTON_ACTION_TOGGLE, 0 }, // Toggle Relay #0
{ 0xE0E0A05F, IR_BUTTON_ACTION_TOGGLE, 1 }, // Toggle Relay #1
{ 0xE0E0609F, IR_BUTTON_ACTION_TOGGLE, 2 }, // Toggle Relay #2
{ 0xE0E010EF, IR_BUTTON_MODE_TOGGLE, 3 }, // Toggle Relay #3
{ 0xE0E0906F, IR_BUTTON_MODE_TOGGLE, 4 }, // Toggle Relay #4
{ 0xE0E050AF, IR_BUTTON_MODE_TOGGLE, 5 }, // Toggle Relay #5
{ 0xE0E010EF, IR_BUTTON_ACTION_TOGGLE, 3 }, // Toggle Relay #3
{ 0xE0E0906F, IR_BUTTON_ACTION_TOGGLE, 4 }, // Toggle Relay #4
{ 0xE0E050AF, IR_BUTTON_ACTION_TOGGLE, 5 }, // Toggle Relay #5
{ 0xE0E030CF, IR_BUTTON_MODE_TOGGLE, 6 }, // Toggle Relay #6
{ 0xE0E0B04F, IR_BUTTON_MODE_TOGGLE, 7 } // Toggle Relay #7
//{ 0xE0E0708F, IR_BUTTON_MODE_TOGGLE, 8 } //Extra Button
{ 0xE0E030CF, IR_BUTTON_ACTION_TOGGLE, 6 }, // Toggle Relay #6
{ 0xE0E0B04F, IR_BUTTON_ACTION_TOGGLE, 7 } // Toggle Relay #7
//{ 0xE0E0708F, IR_BUTTON_ACTION_TOGGLE, 8 } //Extra Button
//{ 0xE0E08877, IR_BUTTON_MODE_TOGGLE, 9 } //Extra Button
//{ 0xE0E08877, IR_BUTTON_ACTION_TOGGLE, 9 } //Extra Button
};
#endif
@ -170,7 +170,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xFFB24D, IR_BUTTON_MODE_TOGGLE, 0 } // Toggle Relay #0
{ 0xFFB24D, IR_BUTTON_ACTION_TOGGLE, 0 } // Toggle Relay #0
};
@ -198,35 +198,35 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xF700FF, IR_BUTTON_MODE_BRIGHTER, 1 },
{ 0xF7807F, IR_BUTTON_MODE_BRIGHTER, 0 },
{ 0xF740BF, IR_BUTTON_MODE_STATE, 0 },
{ 0xF7C03F, IR_BUTTON_MODE_STATE, 1 },
{ 0xF720DF, IR_BUTTON_MODE_RGB, 0xFF0000 },
{ 0xF7A05F, IR_BUTTON_MODE_RGB, 0x00FF00 },
{ 0xF7609F, IR_BUTTON_MODE_RGB, 0x0000FF },
{ 0xF7E01F, IR_BUTTON_MODE_RGB, 0xFFFFFF },
{ 0xF710EF, IR_BUTTON_MODE_RGB, 0xD13A01 },
{ 0xF7906F, IR_BUTTON_MODE_RGB, 0x00E644 },
{ 0xF750AF, IR_BUTTON_MODE_RGB, 0x0040A7 },
{ 0xF7D02F, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xF730CF, IR_BUTTON_MODE_RGB, 0xE96F2A },
{ 0xF7B04F, IR_BUTTON_MODE_RGB, 0x00BEBF },
{ 0xF7708F, IR_BUTTON_MODE_RGB, 0x56406F },
{ 0xF7F00F, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xF708F7, IR_BUTTON_MODE_RGB, 0xEE9819 },
{ 0xF78877, IR_BUTTON_MODE_RGB, 0x00799A },
{ 0xF748B7, IR_BUTTON_MODE_RGB, 0x944E80 },
{ 0xF7C837, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FADE },
{ 0xF728D7, IR_BUTTON_MODE_RGB, 0xFFFF00 },
{ 0xF7A857, IR_BUTTON_MODE_RGB, 0x0060A1 },
{ 0xF76897, IR_BUTTON_MODE_RGB, 0xEF45AD },
{ 0xF7E817, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_SMOOTH }
{ 0xF700FF, IR_BUTTON_ACTION_BRIGHTER, 1 },
{ 0xF7807F, IR_BUTTON_ACTION_BRIGHTER, 0 },
{ 0xF740BF, IR_BUTTON_ACTION_STATE, 0 },
{ 0xF7C03F, IR_BUTTON_ACTION_STATE, 1 },
{ 0xF720DF, IR_BUTTON_ACTION_RGB, 0xFF0000 },
{ 0xF7A05F, IR_BUTTON_ACTION_RGB, 0x00FF00 },
{ 0xF7609F, IR_BUTTON_ACTION_RGB, 0x0000FF },
{ 0xF7E01F, IR_BUTTON_ACTION_RGB, 0xFFFFFF },
{ 0xF710EF, IR_BUTTON_ACTION_RGB, 0xD13A01 },
{ 0xF7906F, IR_BUTTON_ACTION_RGB, 0x00E644 },
{ 0xF750AF, IR_BUTTON_ACTION_RGB, 0x0040A7 },
{ 0xF7D02F, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xF730CF, IR_BUTTON_ACTION_RGB, 0xE96F2A },
{ 0xF7B04F, IR_BUTTON_ACTION_RGB, 0x00BEBF },
{ 0xF7708F, IR_BUTTON_ACTION_RGB, 0x56406F },
{ 0xF7F00F, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xF708F7, IR_BUTTON_ACTION_RGB, 0xEE9819 },
{ 0xF78877, IR_BUTTON_ACTION_RGB, 0x00799A },
{ 0xF748B7, IR_BUTTON_ACTION_RGB, 0x944E80 },
{ 0xF7C837, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_FADE },
{ 0xF728D7, IR_BUTTON_ACTION_RGB, 0xFFFF00 },
{ 0xF7A857, IR_BUTTON_ACTION_RGB, 0x0060A1 },
{ 0xF76897, IR_BUTTON_ACTION_RGB, 0xEF45AD },
{ 0xF7E817, IR_BUTTON_ACTION_EFFECT, LIGHT_EFFECT_SMOOTH }
};


+ 23
- 0
code/espurna/libs/BasePin.h View File

@ -0,0 +1,23 @@
/*
Part of BUTTON module
Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
*/
#pragma once
// base interface for generic pin handler.
class BasePin {
public:
BasePin(unsigned char pin) :
pin(pin)
{}
virtual void pinMode(int8_t mode) = 0;
virtual void digitalWrite(int8_t val) = 0;
virtual int digitalRead() = 0;
const unsigned char pin;
};

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

@ -0,0 +1,123 @@
/*
Original code:
Debounce buttons and trigger events
Copyright (C) 2015-2018 by Xose Pérez <xose dot perez at gmail dot com>
The DebounceEvent library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The DebounceEvent library 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the DebounceEvent library. If not, see <http://www.gnu.org/licenses/>.
----------------------------------------------------------------------------------
Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
Modified to include generic INPUT / OUTPUT pin support through a custom interface.
Definitions are incompatible with DebounceEvent, you should not include it's headers.
*/
#pragma once
#include <Arduino.h>
#include <functional>
#include <memory>
#include "BasePin.h"
namespace debounce_event {
constexpr const unsigned long DebounceDelay = 50UL;
constexpr const unsigned long RepeatDelay = 500UL;
class EventEmitter;
namespace types {
enum class Mode {
Pushbutton,
Switch
};
enum class DefaultState {
Low,
High
};
enum class PinMode {
Input,
InputPullup,
InputPulldown
};
struct Config {
Mode mode;
DefaultState default_state;
PinMode pin_mode;
};
enum Event {
EventNone,
EventChanged,
EventPressed,
EventReleased
};
using Pin = std::shared_ptr<BasePin>;
using EventHandler = std::function<void(const EventEmitter& self, types::Event event, uint8_t count, unsigned long length)>;
}
class EventEmitter {
public:
EventEmitter(types::Pin pin, const types::Config& config = {types::Mode::Pushbutton, types::DefaultState::High, types::PinMode::Input}, unsigned long delay = DebounceDelay, unsigned long repeat = RepeatDelay);
EventEmitter(types::Pin pin, types::EventHandler callback, const types::Config& = {types::Mode::Pushbutton, types::DefaultState::High, types::PinMode::Input}, unsigned long delay = DebounceDelay, unsigned long repeat = RepeatDelay);
types::Event loop();
bool isPressed();
const types::Pin getPin() const;
const types::Config getConfig() const;
unsigned long getEventLength();
unsigned long getEventCount();
private:
types::Pin _pin;
types::EventHandler _callback;
const types::Config _config;
const bool _is_switch;
const bool _default_status;
const unsigned long _delay;
const unsigned long _repeat;
bool _status;
bool _ready;
bool _reset_count;
unsigned long _event_start;
unsigned long _event_length;
unsigned char _event_count;
};
} // namespace debounce_event

+ 1
- 1
code/espurna/lightfox.ino View File

@ -55,7 +55,7 @@ void _lightfoxWebSocketOnConnected(JsonObject& root) {
for (byte id=0; id<buttonsCount; id++) {
JsonObject& node = rfb.createNestedObject();
node["id"] = id;
node["relay"] = getSetting("btnRelay", id, "0");
node["relay"] = getSetting({"btnRelay", id}, 0);
}
}


+ 2547
- 2546
code/espurna/static/index.all.html.gz.h
File diff suppressed because it is too large
View File


+ 2353
- 2352
code/espurna/static/index.light.html.gz.h
File diff suppressed because it is too large
View File


+ 2415
- 2413
code/espurna/static/index.lightfox.html.gz.h
File diff suppressed because it is too large
View File


+ 1985
- 1983
code/espurna/static/index.rfbridge.html.gz.h
File diff suppressed because it is too large
View File


+ 3330
- 3329
code/espurna/static/index.rfm69.html.gz.h
File diff suppressed because it is too large
View File


+ 2509
- 2508
code/espurna/static/index.sensor.html.gz.h
File diff suppressed because it is too large
View File


+ 2403
- 2401
code/espurna/static/index.small.html.gz.h
File diff suppressed because it is too large
View File


+ 1969
- 1967
code/espurna/static/index.thermostat.html.gz.h
File diff suppressed because it is too large
View File


+ 0
- 1
code/espurna/ws.ino View File

@ -413,7 +413,6 @@ void _wsOnConnected(JsonObject& root) {
root["sdk"] = ESP.getSdkVersion();
root["core"] = getCoreVersion();
root["btnDelay"] = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY);
root["webPort"] = getSetting("webPort", WEB_PORT);
root["wsAuth"] = getSetting("wsAuth", 1 == WS_AUTHENTICATION);
root["hbMode"] = getSetting("hbMode", HEARTBEAT_MODE);


+ 7
- 7
code/html/index.html View File

@ -374,16 +374,16 @@
</div>
<div class="pure-g module module-btn">
<label class="pure-u-1 pure-u-lg-1-4">Double click delay</label>
<input name="btnDelay" class="pure-u-1 pure-u-lg-1-4" type="number" action="reboot" min="0" step="100" max="1000" tabindex="6" />
<label class="pure-u-1 pure-u-lg-1-4">Click repeat delay</label>
<input name="btnRepDel" class="pure-u-1 pure-u-lg-1-4" type="number" action="reboot" min="0" step="100" max="1000" tabindex="6" />
<div class="pure-u-0 pure-u-lg-1-2"></div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
Delay in milliseconds to detect a double click (from 0 to 1000ms).<br />
The lower this number the faster the device will respond to button clicks but the harder it will be to get a double click.
Increase this number if you are having trouble to double click the button.
Set this value to 0 to disable double click. You won't be able to set the device in AP mode manually but your device will respond immediately to button clicks.<br />
You will have to <strong>reboot the device</strong> after updating for this setting to apply.
Delay in milliseconds to detect a double or triple click (from 0 to 1000ms).<br />
The lower this number the faster the device will respond to button clicks but the harder it will be to get the expected event.
Increase this number if you are having trouble triggering the event.
Set this value to 0 to disable repeat detection, device will respond immediately to a single button click. When using default configuration, consider that this will disable the SoftAP button action.<br />
You will have to <strong>reboot the device</strong> to apply this setting.
</div>
</div>


+ 0
- 1
code/platformio.ini View File

@ -106,7 +106,6 @@ lib_deps =
ArduinoJson@5.13.4
https://github.com/marvinroger/async-mqtt-client#v0.8.1
Brzo I2C
https://github.com/xoseperez/debounceevent.git#2.0.5
https://github.com/xoseperez/eeprom_rotate#0.9.2
Embedis
https://github.com/plerup/espsoftwareserial#3.4.1


+ 1
- 1
code/test/build/basic.h View File

@ -1,5 +1,5 @@
#define LED1_PIN 0
#define RELAY1_PIN 0
#define BUTTON1_PIN 0
#define BUTTON1_MODE BUTTON_PUSHBUTTON
#define BUTTON1_CONFIG BUTTON_PUSHBUTTON
#define BUTTON1_RELAY 1

Loading…
Cancel
Save