Giter Site home page Giter Site logo

lennarthennigs / button2 Goto Github PK

View Code? Open in Web Editor NEW
456.0 13.0 78.0 143 KB

Arduino/ESP button library that provides callback functions to track single, double, triple and long clicks. It also takes care of debouncing.

License: MIT License

C++ 100.00%
arduino esp8266 embedded c-plus-plus hardware mbed arduino-library esp32 button touch

button2's Introduction

Button2

Arduino/ESP library to simplify working with buttons.

Description

This library allows you to use callback functions to track single, double, triple and long clicks. Alternatively, it provides function to use in your main loop(). The library also takes care of debouncing. Using this lib will reduce and simplify your source code significantly.

It has been tested with Arduino, ESP8266 and ESP32 devices.

To see the latest changes to the library please take a look at the Changelog.

If you find this library helpful please consider giving it a ⭐️ at GitHub and/or buy me a ☕️.

Thank you!

How To Use

This library allows you to define a button and uses callback functions to detect different types of button interactions. If you don't want to use callback there are also functions available for using it in your code's main loop().

Definition

  • Include the library on top
 #include "Button2.h"
  • Define the button either using the constructor or the begin() function.
  void begin(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow  = true);

Button Types

  • You can use the class for "real" buttons (pullup, pulldown, and active low).
  • Per default the button pins are defined as INPUT_PULLUP. You can override this upon creation.
   #include "Button2.h"
   #define BUTTON_PIN D3

   Button2 button;

   void setup() {
     button.begin(BUTTON_PIN);
  }
  • You can also the library with other types of buttons, e.g. capacitive touch or ones handled via I2C. See the section on defining custom handlers below.

Callback Handler

  • Instead of frequently checking the button state in your main loop() this class allows you to assign callback functions.

  • You can define callback functions to track various types of clicks:

    • setTapHandler() will be be called when any click occurs. This is the most basic handler. It ignores all timings built-in the library for double or triple click detection.
    • setClickHandler() will be triggered after a single click occurred.
    • setChangedHandler(), setPressedHandler() and setReleasedHandler() allow to detect basic interactions.
    • setLongClickDetectedHandler() will be triggered as soon as the long click timeout has passed.
    • setLongClickHandler() will be triggered after the button has released.
    • setDoubleClickHandler() and setTripleClickHandler() detect complex interactions.
  • Note: You will experience a short delay with setClickHandler() and setLongClickHandler() as need to check whether a long or multi-click is in progress. For immediate feedback use setTapHandler()or setLongClickDetectedHandler()

  • You can assign callback functions for single or for multiple buttons.

  • You can track individual or multiple events with a single handler.

  • Please take a look at the included examples (see below) to get an overview over the different callback handlers and their usage.

  • All callback functions need a Button2 reference parameter. There the reference to the triggered button is stored. This can used to call status functions, e.g. wasPressedFor().

Longpress Handling

  • There are two possible callback functions: setLongClickDetectedHandler() and setLongClickHandler().
  • setLongClickDetectedHandler() will be called as soon as the defined timeout has passed.
  • setLongClickHandler() will only be called after the button has been released.
  • setLongClickDetectedRetriggerable(bool retriggerable) allows you to define whether want to get multiple notifications for a single long click depending on the timeout.
  • getLongClickCount() gets you the number of long clicks – this is useful when retriggerable is set.

The Loop

  • For the class to work, you need to call the button's loop() member function in your sketch's loop() function.
   #include "Button2.h"
   #define BUTTON_PIN D3

   Button2 button;

   void handleTap(Button2& b) {
    // check for really long clicks
    if (b.wasPressedFor() > 1000) {
    // do something
    }
   }

   void setup() {
     button.begin(BUTTON_PIN);
     button.setTapHandler(handleTap);
  }

  void loop() {
     button.loop();
  }
  • As the loop()function needs to be called continuously, delay() and other blocking functions will interfere with the detection of clicks. Consider cleaning up your loop or call the loop() function via an interrupt.
  • Please see the examples below for more details.

Using an timer interrupt instead

  • Alternatively, you can call the button's loop() function via a timer interrupt.
  • I haven't tried this extensively, USE THIS AT YOUR OWN RISK!
  • You need make sure that the interval is quick enough that it can detect your timeouts (see below).
  • There is an example for the ESP32 ESP32TimerInterrupt.ino that I tested.

Timeouts

  • The default timeouts for events are (in ms):
  #define BTN_DEBOUNCE_MS 50
  #define BTN_LONGCLICK_MS 200
  #define BTN_DOUBLECLICK_MS 300
  • You can define your own timeouts by using these setter functions:
    • void setDebounceTime(unsigned int ms)
    • void setLongClickTime(unsigned int ms)
    • void setDoubleClickTime(unsigned int ms)
  • There are also getter functions available, if needed.

Using Button2 in the main loop()

  • Even though I suggest to use handlers for tracking events, you can also use Button2 to check button's state in the main loop
  • bool wasPressed() allows you to check whether the button was pressed
  • clickType read(bool keepState = false) gives you the type of click that took place
  • clickType wait(bool keepState = false) combines read() and wasPressed() and halts execution until a button click was detected. Thus, it is blocking code.
  • The clickType is an enum defined as...
    enum clickType {
      single_click, 
      double_click, 
      triple_click, 
      long_click,
      empty
    };
  • There are also dedicated waits (waitForClick(), waitForDouble(), waitForTriple() and waitForLong()) to detect a specific type
  • The read() and the wait functions will reset the state of wasPressed() unless specified otherwise (via a bool parameter)
  • resetPressedState() allows you to clear value returned by wasPressed() – it is similar to passing keepState = false for read() or wait().
  • Check out the ButtonLoop.ino example to see it in action

Status Functions

  • There are several status functions available to check the status of a button:
unsigned int wasPressedFor() const;
byte getNumberOfClicks() const;
byte getType() const;
boolean isPressed() const;
boolean isPressedRaw() const;
bool wasPressed() const;

IDs for Button Instances

  • Each button instance gets a unique (auto incremented) ID upon creation.
  • You can get a buttons' ID via getID().
  • Alternatively, you can use setID(int newID) to set a new one. But then you need to make sure that they are unique.

Creating A Custom Button State Handler

  • Out of the box Button2 supports regular hardware buttons.
  • If you want to add other button types you need to define your own function that tracks the state of the button.
  • Use setButtonStateFunction() to assign it to your Button2 instance
  • Make the button pin 'VIRTUAL', i.e. by calling button.begin(VIRTUAL_PIN);
  • And don't forget to initialize the button as this cannot be handled by Button2
  • See ESP32CapacitiveTouch.ino, M5StackCore2CustomHandler.ino, and CustomButtonStateHandler.ino as examples.

Examples

Class Definition

The button class offers a few additional functions, please take a look at the Class Definition below.

See below the constructors and member functions the library provides:

Button2();
Button2(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true);

void begin(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow  = true);

void setDebounceTime(unsigned int ms);
void setLongClickTime(unsigned int ms);
void setDoubleClickTime(unsigned int ms);

unsigned int getDebounceTime();
unsigned int getLongClickTime();
unsigned int getDoubleClickTime();
byte getPin();

void reset();

void setButtonStateFunction(StateCallbackFunction f);

void setChangedHandler(CallbackFunction f);
void setPressedHandler(CallbackFunction f);
void setReleasedHandler(CallbackFunction f);

void setTapHandler(CallbackFunction f);
void setClickHandler(CallbackFunction f);
void setDoubleClickHandler(CallbackFunction f);
void setTripleClickHandler(CallbackFunction f);

void setLongClickHandler(CallbackFunction f);
void setLongClickDetectedHandler(CallbackFunction f);
void setLongClickDetectedRetriggerable(bool retriggerable);
void byte getLongClickCount() const;

unsigned int wasPressedFor() const;
void resetPressedState();
byte resetClickCount();

boolean isPressed() const;
boolean isPressedRaw() const;

bool wasPressed() const;
clickType read(bool keepState = false);
clickType wait(bool keepState = false);
void waitForClick(bool keepState = false);
void waitForDouble(bool keepState = false);
void waitForTriple(bool keepState = false);
void waitForLong(bool keepState = false);

byte getNumberOfClicks() const;
byte getType() const;
String clickToString(clickType type) const;

int getID() const;
void setID(int newID);

bool operator == (Button2 &rhs);

void loop();

Installation

Open the Arduino IDE choose "Sketch > Include Library" and search for "Button2". Or download the ZIP archive (https://github.com/lennarthennigs/Button2/zipball/master), and choose "Sketch > Include Library > Add .ZIP Library..." and select the downloaded file.

License

MIT License

Copyright (c) 2017-2023 Lennart Hennigs

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

button2's People

Contributors

alex-s-v avatar jacobdekeizer avatar lennarthennigs avatar mscreations avatar ovidiupruteanu avatar per1234 avatar ryancasler avatar skelstar avatar tommyc81 avatar w4ilun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

button2's Issues

Advices for implementing a speed-sensitive button-press control

@LennartHennigs Hi, in my project I'd like to implement a button that when pressed for long, the value displayed in the screen (say, an integer) increases, slowly at the beginning and then faster, according to how long I've been pressing the button.
How can I implement that with this library? Is there an example of this? Is setLongClickDetectedRetriggerable() the function to use?
Btw, can it be added as a feature?

Question: what should `wasPressedFor()`return for double and triple clicks?

Hey,
I noticed that wasPressedFor() always the returns the time for the last click.
This sounds ok but for double and triple clicks it might not be helpful.

What would you expect?

  • the total time (i.e. the sum of the clicks)?
  • the time for single and long press and nothing for double and triple?
  • something else?

Ideas are welcome.

bmp.h

Hi! Please link where can I get the bmp.h library?

Example for 2 buttons and multi?

Hi,
you have given an example of two buttons, you have given me in example of multi.
Well, but I'm sorry it is not obvious to me how to get two buttons with multi.
Could you please provide an example for that.

I have tried:
Button2 up = Button2(BUTTON_UP);
Button2 down = Button2(BUTTON_DOWN);
and
in Loop()
up.loop();
down.loop();

but then how can i get two functions, when the long press handler in your reference is
void longpress(Button2& btn) {
...
}

I don't see in that handler any reference to the previously defined "button" in your example that would in my case be "up" and "down".

Would you be so kind and give a complete example for at least two buttons?
thank you

Laszlo

Error Compiling For ESP32 C3

When compiling a Button2 sketch using an ESP32 C3 board (I tried 2 different brands, DFRobot and Adafruit), I get the following error:

c:\LIBRARY DIRECTORY\Button2\src\Button2.cpp: In member function 'byte Button2::_getState()':
c:\LIBRARY DIRECTORY\Button2\src\Button2.cpp:293:18: error: 'touchRead' was not declared in this scope
       int capa = touchRead(pin);
                  ^~~~~~~~~
c:\LIBRARY DIRECTORY\Button2\src\Button2.cpp:293:18: note: suggested alternative: 'timerRead'
       int capa = touchRead(pin);
                  ^~~~~~~~~
                  timerRead
exit status 1
Compilation error: exit status 1

One thing that sets the C3 apart from other members of the ESP32 family is the fact that it doesn't support touch. I can't seem to figure out why it's reading this as capacitive. Here are the relevant sections of my sketch:

Button2 button_0, button_1, button_2, button_3, button_4, button_5, button_6, button_7;
Button2 myButtons[] = { button_0, button_1, button_2, button_3, button_4, button_5, button_6, button_7 };
int buttonPins[] = {A0, A1, A2, A3, SDA, SCL, TX, RX};
int numButtons = 8;

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("Initialized");
  for (int i = 0; i < numButtons; i++) {
    myButtons[i].begin(buttonPins[i], INPUT_PULLUP, false, true);
    myButtons[i].setClickHandler(clickHandler);
    myButtons[i].setDoubleClickHandler(doubleHandler);
    myButtons[i].setLongClickDetectedHandler(longHandler);
    myButtons[i].setReleasedHandler(released);
    myButtons[i].setLongClickTime(800);
    myButtons[i].setDoubleClickTime(400);
    myButtons[i].setDebounceTime(75);
  }
}

And of course I have all the relevant callbacks and whatnot.

Now, If I switch to an ESP32 S2 board, the exact same sketch compiles perfectly with zero changes. So, I assume there is something wrong in the board definition or the variants pin definition for the C3 boards but for the life of me I can't find it. I also tried to define a custom state function for all of the buttons and that didn't help. I still got the same error when compiling. Any advice on where to look and what might need to be changed? I'm using the latest version of the ESP32 Core for Arduino, v2.0.5.
https://github.com/espressif/arduino-esp32/releases/tag/2.0.5
Thanks so much!!

How to handle initial button state?

Consider the following button:
Button2 bigRedButton = Button2(bigRedButtonPin, INPUT_PULLUP, false, false);

For some weird reason, the button is pressed while the Arduino reboots. This doesn't fire any callbacks. I have tried setPressedHandler, setReleasedHandler and setChangedHandler. Since the button is not active low, shouldn't it trigger on boot? It works fine if I release and press it after booting.

Button click unreliable

I'm finding the single click function doesn't always register (works 80% or less of the time). I'm using a nodemcu V2 and clickable encoder. I have tried replacing the encoder. I can see the blue led light up on the nodemcu everytime I click it even when it doesn't register. Perhaps a timing issue? The sketch is basically built off the demo. I'm using visual studio code with platformio. Using the latest encoder library I pulled from github and the button2 library is from platformio. I tried using your latest one from github and the buttons wouldn't register at all.

#define ROTARY_PIN1 D2
#define ROTARY_PIN2 D3
#define BUTTON_PIN D4

/////////////////////////////////////////////////////////////////

ESPRotary r = ESPRotary(ROTARY_PIN1, ROTARY_PIN2, 2 );
Button2 b = Button2(BUTTON_PIN);

void setup() {
Serial.begin(9600);
delay(1000);
Serial.println("\n\nFocusrite Knob");

setupWifi();
delay(3000);
broadcast();
getPort();

setupClient();

delay(50);

Serial.println("\n\nInitialized");

r.setChangedHandler(rotate);
r.setLeftRotationHandler(showDirection);
r.setRightRotationHandler(showDirection);

b.setClickHandler(muteVol);
b.setLongClickHandler(resetPosition);

}

void loop() {
r.loop();
b.loop();
}

button.isPressed(); seems to stay latched.

Hi. I am wiring a GUI for a digital watch/wearable. I am using the Button2 library and the isPressed() method to determine when selections are made. Perhaps my understanding of the the method is incorrect. I assume if I have a button e.g. buttonBack and I use
if (buttonBack.isPressed()){ insert code }

this will only be executed if the button is currently being pressed. What I am finding is that this seems to stay "latched" on many occasions and results in buttonBack.isPressed() evaluating to a value of 1 even if the button is not being pressed. I have played around with the debounce times and do not believe it is noise. I will include the loop portion of my code and delete some of the lines that are not relevant so you have an idea of what I am doing.
`void loop() {

switch (mode){
case 0 :

if (oldMode!=mode){
int numMenuItems = 4;
buttonUp.setClickHandler([scrollDirection, numMenuItems, bitmaps1=bitmaps1, menuLabels1=menuLabels1](Button2 &btn){
scrollMenu(RIGHT, numMenuItems, bitmaps, menuLabels,btn);
});
buttonUp.setLongClickDetectedHandler([scrollDirection, numMenuItems, bitmaps1=bitmaps1, menuLabels1=menuLabels1](Button2 &btn){
scrollMenu(RIGHT, numMenuItems, bitmaps, menuLabels,btn);
});
buttonUp.setLongClickDetectedRetriggerable(1);
buttonDown.setClickHandler([scrollDirection, numMenuItems, bitmaps1=bitmaps1, menuLabels1=menuLabels1](Button2 &btn){
scrollMenu(LEFT, numMenuItems, bitmaps, menuLabels,btn);
});
buttonDown.setLongClickDetectedHandler([scrollDirection, numMenuItems, bitmaps1=bitmaps1, menuLabels1=menuLabels1](Button2 &btn){
scrollMenu(LEFT, numMenuItems, bitmaps, menuLabels,btn);
});
buttonDown.setLongClickDetectedRetriggerable(1);
currentMenuSelection=0;

}
if (buttonBack.isPressed()){
mode=1;
oldMode=0;
break;
}
if (buttonEnter.isPressed()){
mode=currentMenuSelection+2;
break;
}

oldMode=mode;
loopbuttons();
break;

case 1:
if (buttonUp.isPressed()|buttonDown.isPressed()){
mode=0;
oldMode=1;
break;
}
printScreen();
loopbuttons();
break;

case 2: //settings
if (oldMode!=mode){

 }

if (buttonBack.isPressed()){
mode=0;
oldMode=1;
break;
}
oldMode=mode;
loopbuttons();
break;

case 3: //Alarm
if (oldMode!=mode){
}
if (buttonBack.isPressed()){
mode=0;
oldMode=1;
break;
}
oldMode=mode;
loopbuttons();
break;

case 4: //Stopwatch
if (oldMode!=mode){
}
if (buttonBack.isPressed()){
mode=0;
oldMode=1;
break;
}
oldMode=mode;
loopbuttons();
break;

case 5: //Flashlight
if (oldMode!=mode){
}
if (buttonBack.isPressed()){
mode=0;
oldMode=1;
break;
}
oldMode=mode;
loopbuttons();
break;
}

}

one thing of interest is that the code may encounter the ' if (buttonBack.isPressed()){' multiple times prior to seeing loopbuttons(); which is simply the following:
'void loopbuttons(){
buttonUp.loop();buttonEnter.loop();buttonDown.loop();buttonBack.loop();
if (alarmFlag==1){
alarmRing();
}
if ((millis()-lastButtonPressedTime)>(buttonInactiveSleepTime*1000)){
deepSleep(dummyButton);
}
}'
At first I thought this was the issue, but even If I add loopbuttons(); at various locations, it still doesn't seem to work. I can always use a button clickHandler, but that is a bunch more code than simply using isPressed();

pressed and released reversed in code?

pressed = activeLow ? HIGH : LOW;

This code:

pressed = activeLow ? HIGH : LOW;
released = activeLow ? LOW : HIGH;

If activeLow is true (i.e. INPUT_PULLUP pin mode used), shouldn't the (button) 'pressed' state be a LOW reading on the pin? And vice versa of the 'released' state - this would be a HIGH reading on the pin (i.e. 'released' is when you're NOT pressing/pushing the button).

I'm trying to find a decent Button library, but want to understand the source code before I dig in. Just checking if I'm reading the source code correctly. The seemingly reversed references to 'pressed' and 'released' is confusing, chances are that I simply got it wrong. Appreciate any clarification you have.

Detect long press while button is pressed

Hi, from what I understand in the code now, the long press only triggers the callback when the long press is finished. Is there a way to detect a long press while the button is still being pressed?

Change pin assignments at runtime

Hi.

Thank you very much for your library. Fantastic, a time saver!

I'm using it on a project (a CO2 monitor) and I'm adding the possibility to reverse the display 180º with a menu option.
In a board like the TTGO T-Tdisplay, when display is reversed I need also to reverse the functionality of the two buttons it has.

Until now I was initializing buttons as:

Button2 btnUp(BTN_UP);   // Initialize the up button
Button2 btnDwn(BTN_DWN); // Initialize the down button
void buttonsInit() {
  btnUp.setLongClickTime(LONGCLICK_TIME_MS);  
  btnUp.setLongClickHandler([](Button2 &b) { nav.doNav(enterCmd); });
  btnUp.setClickHandler([](Button2 &b) {
    // Up
    nav.doNav(downCmd);
  });

  btnDwn.setLongClickTime(LONGCLICK_TIME_MS);
  btnDwn.setLongClickHandler([](Button2 &b) { nav.doNav(escCmd); });
  btnDwn.setClickHandler([](Button2 &b) {
    // Down
    nav.doNav(upCmd);
  });
}

https://github.com/melkati/CO2-Gadget/blob/8b55114596b1c5b811b091d794e3dccd75928657/CO2_Gadget_Buttons.h#L17-L34

What is the best way to "reverse the buttons" at execution time, so now btnUp is assigned to pin BTN_DWN (instead of BTN_UP) and btnDwn to pin BTN_UP (instead of BTN_DWN)?

private -> protected

One more comment, if the private variables was protected, then it would be easy to create a derived class.

Is there a way to run the button.loop function in the background using an interrupt timer ?

Hello Mr. Hennings,

First thank you for your very useful library, Button2.

I would like the button.loop() function to run in the background, from a timer interrupt (like one of the timers on STM32F4xx) so that it would be independent of the aleas of other function execution lengths, and also avoid to periodically call the button.loop() function completely. The long click, single, double and triple click would simply set a flag that can be reset at any time after reading the status of the flag(s).

I have to say that I tried to call the button.loop() function from a timer interrupt function but without success.

Thank you for your help.

Regards,
Rene-Jean Mercier
[email protected]

ESP32 Compiler warning

Setting my compiler to all messages I get this warning:

D:\5_Tinker\Arduino\libraries\Button2\src\Button2.cpp: In member function 'void Button2::loop()':
D:\5_Tinker\Arduino\libraries\Button2\src\Button2.cpp:181:11: warning: comparison is always true due to limited range of data type [-Wtype-limits]
   if (pin > -1) {
           ^

Since pin numbers are defined as uint8 this comparison seem to be reconsidered isn't it?

LongClickDetectedHandler triggered after boot?

I tried to replace the setLongClickHandler(handler) ...which works fine (but you don't know if your press was long enough until you release the button), by setLongClickDetectedHandler(handler) and I noticed a side effect.
Look at the log below and my comments in bold.

And this side effect is consistent. You might want to look into it...

--- Terminal on /dev/ttyACM0 | 115200 8-N-1
--- Available filters and text transformations: colorize, debug, default,
direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at https://bit.ly/pio-monitor-filters
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H

Starting MMT Power Supply Interface !!!

PG set to PG40
EEPROM Beginning : 0
EEPROM End : 16384
System Voltage Set Value : 10.000
Corresponding DAC Voltage Output : 1.65
Corresponding DAC Binary Voltage Output : 2047
System Current Set Value : 0.500
Corresponding DAC Current Output : 0.82
Corresponding DAC Binary Current Output : 1023
System Input Voltage        : 4.7820001
Output Voltage              : 7.4822955
System Output Current       : 0.0019200
Z Output                    : 3897.03
System Power W              : 0.0090394


(1)** <------------------------------------------------------------- this was a long click (not ok) ... it happens only once after boot-up, as if no case in the function (see function below) was satisfied.***
---long click (1)
**<------------------------------------------------------------- this was a long click  (ok)**
ENTERING SELECTION MODE NORMAL OPERATION

---long click (1)
**<------------------------------------------------------------- this was a long click  (ok)**
Getting out of the Parameter Selection function

ENTERING MODIFICATION MODE

---long click (1)
**<------------------------------------------------------------- this was a long click  (ok)**
System Voltage Set Value : 10.000
Corresponding DAC Voltage Output : 1.65
Corresponding DAC Binary Voltage Output : 2047
Getting out of the Parameter Modificaton function

---double click (2)
**<------------------------------------------------------------- this was a long click  (ok)**
ENTERING PRESET SELECTION MODE

----Set pointer to the selected window
Set Coordinates To Preset Window
SetCoordinatesToPresetWindow preset3V3
*****Highlight Preset Window
*****Initialize Preset Window
CW Direction -- Encoder Value : 1
*******1----Set pointer to the selected window
++++Give Preset Colors To Window : preset5V0
Set Coordinates To Preset Window
SetCoordinatesToPresetWindow preset5V0
*****Highlight Preset Window
*****Initialize Preset Window
---double click (1)
**<------------------------------------------------------------- this was a long click (not ok) ... it appens consistently.**
---long click (1)
**<------------------------------------------------------------- this was a long click  (ok)**
Preset Value Selected saved to EEPROM
System Voltage Set : 5.000
System Current Set : 0.500
System Input Voltage        : 4.7900000
Output Voltage              : 7.4725275
System Output Current       : 0.0019200
Z Output                    : 3891.94
System Power W              : 0.0095182
/*************************************************************************************************************************/
/* BUTTON SWITCH HANDLER SECTION */
/*************************************************************************************************************************/

void handler(Button2& btn) {
  switch (btn.getType()) {
    case long_click:
      myButtonState = ds.ButtonState::longClick;
      Serial.print("---long click ");
      //Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
    break;
  
    case double_click:
      myButtonState = ds.ButtonState::doubleclick;
      Serial.print("---double click ");
      //Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
    break;

    case triple_click:
      myButtonState = ds.ButtonState::tripleClick;
      Serial.print("---triple click");
      //Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
    break;
  
  case single_click:
    myButtonState = ds.ButtonState::click;
    Serial.print("---single click");
    //Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
  break;
  }

  Serial.print(" (");
  Serial.print(btn.getNumberOfClicks());
  Serial.println(")");
}
void FunctionProcessing::buttonSetup() {
  button.begin(ENCODER_SWITCH_PORT,INPUT_PULLUP,false,true); // byte
attachTo, byte buttonMode /* = INPUT_PULLUP */, boolean isCapacitive /* =
false */, boolean activeLow /* = true */

  button.setDebounceTime(50); //
  button.setLongClickTime(500);
  button.setDoubleClickTime(700);

  button.setClickHandler(handler);
  button.setLongClickDetectedHandler(handler); //setLongClickHandler(handler);
  button.setDoubleClickHandler(handler);
  button.setTripleClickHandler(handler);
}

Regards,
Rene-Jean

Originally posted by @renejeanmercier in #43 (comment)

Feature request: be able to set your own _getState() callback function

I wanted the debounce and longpress capability that I enjoy from Button2 library but my input was a samd21 touch sensor. Might also have other inputs such as analog threshold or buttons on i2c IO expander. If we could set a custom _getState() handler and get around the check for valid pin in Button2::loop() then buttons that are not on digitalRead would be possible and a more generic way than the esp touch button implementation. I was able to do it by changing _getState() to virtual and derived class as follows, but it was extra work and I don't like changing libraries and having a bunch of notes about that in my code. Here's what I got that might give you ideas on a better way:

#pragma once
#ifndef Button2cb_h
#define Button2cb_h
#if defined(ARDUINO_ARCH_ESP32) || defined(ESP8266)
#include
#endif
#include "Arduino.h"
#include <Button2.h>
#define VIRTUAL_PIN 254
typedef byte (*ButtonStateCallbackFunction)(void);
class Button2cb : public Button2 {
protected:
ButtonStateCallbackFunction getState_cb = NULL;
public:
void begin(boolean activeLow = true);
boolean isPressedRaw() const;
void setGetStateHandler(ButtonStateCallbackFunction f);
private:
// note, to properly override this in the base class, it has to be made virtual in Button2.h
byte _getState();
};

/////////////////////////////////////////////////////////////////
/*
Button2cb.cpp
/
/////////////////////////////////////////////////////////////////
#include "Button2cb.h"
void Button2cb::begin(boolean activeLow /
= true */)
{
pin = VIRTUAL_PIN; // this gets us past loop()'s (pin != UNDEFINED_PIN) check
longclick_detected_retriggerable = false;
_pressedState = activeLow ? LOW : HIGH;
setDebounceTime(DEBOUNCE_MS);
setLongClickTime(LONGCLICK_MS);
setDoubleClickTime(DOUBLECLICK_MS);
// this constructor allows us to get around setting pinMode on our VIRTUAL_PIN
state = _getState();
prev_state = state;
}
void Button2cb::setGetStateHandler(ButtonStateCallbackFunction f) {
getState_cb = f;
}
boolean Button2cb::isPressedRaw() const { // another digitalRead to work around
if(getState_cb != NULL)
return (getState_cb() == _pressedState);
return false;
}
/////////////////////////////////////////////////////////////////
// note, to properly override this in the base class, it has to be made virtual in Button2.h
byte Button2cb::_getState() {
if(getState_cb != NULL)
{
return getState_cb(); // use our installed callback function to get the virtual pin's state
}
return 0;
}

/////////////////// Now with the new class, I can use the following

Button2cb DebouncerQtColorChange;
// callback function to read our samd21 qTouch via the measure() function to get the analog value of the touch peripheral
byte ButtonQtColorGetState()
{
return (ButtonQtColorChange.measure() > QtThreshold) ? LOW : HIGH;
}

void setup()
{
DebouncerQtColorChange.begin(); // Button2 subclass
DebouncerQtColorChange.setGetStateHandler(ButtonQtColorGetState); // set my custom way to _getState()
DebouncerQtColorChange.setClickHandler(AnimationColorShiftButtonHandler);
DebouncerQtColorChange.setLongClickHandler(AnimationColorShiftButtonHandler);
}

No active HIGH button

ESP32 can wake up from sleep only for active HIGH, therefore most designs use this. Would be nice if this nice piece of code worked for active HIGH buttons.

Interrupt wdt timeout on CPU1

Hi,
when i run the example ESP32TimerInterrupt.ino, it crashed when i click the button, every time.

here the modified code:
#define BUTTON_PIN 35
btn.begin(BUTTON_PIN, INPUT_PULLDOWN, false);

Other code are not modified.

Here's the log:

click
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).

Core 1 register dump:
PC : 0x4008c1f2 PS : 0x00060335 A0 : 0x8008b166 A1 : 0x3ffbf0ec
A2 : 0x3ffb8314 A3 : 0x3ffb81a4 A4 : 0x00000004 A5 : 0x00060323
A6 : 0x00060323 A7 : 0x00000001 A8 : 0x3ffb81a4 A9 : 0x00000018
A10 : 0x3ffb81a4 A11 : 0x00000018 A12 : 0x00000004 A13 : 0x00060323
A14 : 0x007bf328 A15 : 0x003fffff SAR : 0x0000000a EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x4008786d LEND : 0x4008787d LCOUNT : 0xfffffffe
Core 1 was running in ISR context:
EPC1 : 0x400de797 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x00000000

Backtrace: 0x4008c1ef:0x3ffbf0ec |<-CORRUPTED

Core 0 register dump:
PC : 0x4008c38b PS : 0x00060035 A0 : 0x8008ad8f A1 : 0x3ffbea4c
A2 : 0x3ffbf328 A3 : 0xb33fffff A4 : 0x0000abab A5 : 0x00060023
A6 : 0x00060021 A7 : 0x0000cdcd A8 : 0x0000abab A9 : 0xffffffff
A10 : 0x3ffc307c A11 : 0x00000000 A12 : 0x3ffc3078 A13 : 0x00000007
A14 : 0x007bf328 A15 : 0x003fffff SAR : 0x0000001d EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000

It seems the function "onTimer()" costs too much time? But only "btn.loop();"

Any help will be appreciated!

Invalid property in "library.properties" breaks build process in arduino-cli

Hi,

I was having a trouble with Arduino-CLI when using TTGO-TDisplay for the target board, this board's example is using Button2 lib, the example seems working fine in Arduino IDE (the regular with GUI one we are using) but Arduino-CLI is not. When I built with CLI, It showed:

fatal error: Button2.h: No such file or directory

Eventually it is there in the library directory.

I did a further investigation and figured it out that was not the Arduino-cli causing the problem but the Button2 library, there is an invalid property in "library.properties" of it: includes=ButtonCallback.h . IMO, Arduino-cli expected 'ButtonCallback.h' but in the Sketch has #include = "Button2.h" and 'Buttoncallback.h' is not in the lib directory also. I have refered this document.

I deleted the property from the file and everything worked normally again.

2.3.0 breaks at least on RP2040 with type errors

Not happy about pin identifiers and mode...

                 from D:\Electronique\PicoPDSupply\PicoPD_LVGL\PicoPD_LVGL.ino:8:
c:\Users\me\Documents\Arduino\libraries\Button2\src/Hardware.h: In member function 'virtual void ArduinoHardware::pinMode(int, int)':
c:\Users\me\Documents\Arduino\libraries\Button2\src/Hardware.h:42:24: error: invalid conversion from 'int' to 'PinMode' [-fpermissive]
   42 |         ::pinMode(pin, mode);
      |                        ^~~~
      |                        |
      |                        int
In file included from c:\users\me\appdata\local\arduino15\packages\rp2040\hardware\rp2040\3.6.2\arduinocore-api\api\Interrupts.h:8,
                 from c:\users\me\appdata\local\arduino15\packages\rp2040\hardware\rp2040\3.6.2\arduinocore-api\api\arduinoapi.h:29,
                 from C:\Users\me\AppData\Local\Arduino15\packages\rp2040\hardware\rp2040\3.6.2\cores\rp2040/api/ArduinoAPI.h:2,
                 from C:\Users\me\AppData\Local\Arduino15\packages\rp2040\hardware\rp2040\3.6.2\cores\rp2040/Arduino.h:28,
                 from C:\TEMP\arduino\sketches\870F04C926EA2EED0B213104A8CED5D4\sketch\PicoPD_LVGL.ino.cpp:1:
c:\users\me\appdata\local\arduino15\packages\rp2040\hardware\rp2040\3.6.2\arduinocore-api\api\Common.h:98:44: note:   initializing argument 2 of 'void pinMode(pin_size_t, PinMode)'
   98 | void pinMode(pin_size_t pinNumber, PinMode pinMode);
      |                                    ~~~~~~~~^~~~~~~
c:\Users\me\Documents\Arduino\libraries\Button2\src/Hardware.h: In member function 'virtual void ArduinoHardware::digitalWrite(int, int)':
c:\Users\me\Documents\Arduino\libraries\Button2\src/Hardware.h:45:29: error: invalid conversion from 'int' to 'PinStatus' [-fpermissive]
   45 |         ::digitalWrite(pin, value);
      |                             ^~~~~
      |                             |
      |                             int
c:\users\me\appdata\local\arduino15\packages\rp2040\hardware\rp2040\3.6.2\arduinocore-api\api\Common.h:99:51: note:   initializing argument 2 of 'void digitalWrite(pin_size_t, PinStatus)'
   99 | void digitalWrite(pin_size_t pinNumber, PinStatus status);
      |                                         ~~~~~~~~~~^~~~~~

getType() with Long Click Detected

The press type of that is stored for the button is not updated until the button is released isn't it? I ran into a bit of a problem trying to use a multi-type handler with longClickDetected. It would always report the previous click type until I did 2 in a row. But the same setup worked perfectly if I had a separate handler. That's when it occurred to me that the press type might not be updated until the button is released, therefore causing my problem. Might be something to mention as another difference between longClickHandler and longClickDetectedHanlder.
But I love the new custom handler function! I am planning on using a Seesaw GPIO expander from Adafruit for a project and the only thing that has been holding me back is needing to code all of the button handler timing manually. This is wonderful! Thank you!

Read initial value during boot

Hi.
I'm using a 2 state physical switch and an ESP32.
The switch is constant ON, or constant OFF (act as a light switch), and connected as ACTIVE_LOW.

At boot, switch can be "ON" (LOW).
In that case, right after boot sequence, light is switched ON, meaning that setPressedHandler handler called.

Firstly, I'm looking for a way that ON-BOOT-STATE of the switch will be saved as start state.
Secondly, from what I see, inside begin function that state is supposed to be stored, but still, it is not solved:

 state = _getState();
  prev_state = state ; 

Thirdly, adding button2_instance.loop() right after button2_instance.begin(Pin), actually solved is, but still it looks awkward.

Help any assistance to understand how to store ON-BOOT-STATE, for such cases.

Guy

Active low button don't work with the library

Perhaps really silly question, but none of the examples work with my ESP32. I have 3 buttons switching to ground. They work perfectly reliable when just reading the buttons using pinMode(#, INPUT_PULLUP) and digitalRead(#) (0=pressed, 1=not pressed). Very surprisng since the default of the library also seems to be INPUT_PULLUP.
I'm sure it has something to do with configuring the Button2 button using the constructor or begin().
Is it possible to document this configuration in the Readme file?
Many thanks.

capacitive buttons support

proposed patch (tested on esp32)

diff --git a/src/Button2.h b/src/Button2.h
index 503f2b1..2729aca 100644
--- a/src/Button2.h
+++ b/src/Button2.h
@@ -35,6 +35,7 @@
 class Button2 {
   protected:
     byte pin;
+    bool capacitive = false;
     int prev_state;
     int state;
     int pressed;
@@ -60,7 +61,7 @@ class Button2 {
     CallbackFunction triple_cb = NULL;
     
   public:
-    Button2(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true, unsigned int debounceTimeout = DEBOUNCE_MS);
+    Button2(byte attachTo, bool isCapacitive = false, byte buttonMode = INPUT_PULLUP, boolean activeLow = true, unsigned int debounceTimeout = DEBOUNCE_MS);
     void setDebounceTime(unsigned int ms);
     void reset();


diff --git a/src/Button2.cpp b/src/Button2.cpp
index 63667b5..4f09d77 100644
--- a/src/Button2.cpp
+++ b/src/Button2.cpp
@@ -10,10 +10,15 @@
 
 /////////////////////////////////////////////////////////////////
 
-Button2::Button2(byte attachTo, byte buttonMode /* = INPUT_PULLUP */, boolean activeLow /* = true */, unsigned int debounceTimeout /* = DEBOUNCE_MS */) {
+Button2::Button2(byte attachTo, boolean isCapacitive /* = false */, byte buttonMode /* = INPUT_PULLUP */, 
+                boolean activeLow /* = true */, unsigned int debounceTimeout /* = DEBOUNCE_MS */) {
   pin = attachTo;
   setDebounceTime(debounceTimeout);
-  pinMode(attachTo, buttonMode);
+  if (!isCapacitive)
+    pinMode(attachTo, buttonMode);
+  else
+    capacitive = true;
+    
   pressed = activeLow ? HIGH : LOW;
   released = activeLow ? LOW : HIGH;
   state = pressed;
@@ -107,7 +112,15 @@ unsigned int Button2::getClickType() {
 
 void Button2::loop() {
   prev_state = state;
-  state = digitalRead(pin);
+  if (!capacitive)
+    state = digitalRead(pin);
+  else{
+    int capa = touchRead(pin);
+    state = capa > 70 ? HIGH : capa < 30 ? LOW : state;
+  }
 
   // is button pressed?
   if (prev_state == pressed && state == released) {

LongpressHandler demo doesn't work

I've borrowed the code from LongpressHandler demo, and it doesn't work.
Then I just tried the demo, and... it doesn't work either - only the 'welcome message' is shown, and no reaction on clicks.

The 'button' is connected to D1 and GND, so I've adjusted the demo sketch:

#define BUTTON_A_PIN  D1

Platform: ESP8266 (NodeMCU V3) / Arduino IDE 1.8.13 / ESP8266 Core 2.7.4

Missing const-modifiers for methods

There are few methods which don't change the state of Button2 object.
They should be marked with const keywors:

    unsigned int wasPressedFor() const;
    boolean isPressed() const;

    unsigned int getNumberOfClicks() const;
    unsigned int getClickType() const;

multiple ESP32CapacitiveTouch.ino

hi Hennigs, thank you for your awesome library , the esp32 touch sample run well, so I I'd like to implement more than one touch button i.e: (meniu_button ,eq_button volup_button, voldow_down, ). that the code run , but only one the menu_button responding action, please help to validate my below sketch. thank you alot!

/////////////////////////////////////////////////////////////////

#if !defined(ESP32)
#error This sketch needs an ESP32
#else

/////////////////////////////////////////////////////////////////

#include "Button2.h"

/////////////////////////////////////////////////////////////////

Button2 menu_button;
Button2 eq_button;
Button2 volup_button;
Button2 voldow_button;

#define button1 4 // menu-button
#define button2 15 // e button
#define button3 32 // vol +
#define button4 33 // vol -

/////////////////////////////////////////////////////////////////

byte capStateHandler1() {
int capa = touchRead(button1);
return capa < menu_button.getDebounceTime() ? LOW : HIGH;
}
byte capStateHandler2() {
int capa = touchRead(button2);
return capa < eq_button.getDebounceTime() ? LOW : HIGH;
}
byte capStateHandler3() {
int capa = touchRead(button3);
return capa < volup_button.getDebounceTime() ? LOW : HIGH;
}
byte capStateHandler4() {
int capa = touchRead(button4);
return capa < voldow_button.getDebounceTime() ? LOW : HIGH;
}

/////////////////////////////////////////////////////////////////

void setup() {
Serial.begin(9600);
delay(50);
Serial.println("\n\nCapacitive Touch Demo");

menu_button.setDebounceTime(40);
menu_button.setButtonStateFunction(capStateHandler1);
menu_button.setClickHandler(click);
menu_button.setLongClickHandler(longClick);
menu_button.begin(VIRTUAL_PIN);

eq_button.setDebounceTime(40);
eq_button.setButtonStateFunction(capStateHandler2);
eq_button.setClickHandler(eq_click);
eq_button.begin(VIRTUAL_PIN);

volup_button.setDebounceTime(40);
volup_button.setButtonStateFunction(capStateHandler3);
volup_button.setClickHandler(volup_click);
volup_button.begin(VIRTUAL_PIN);

voldow_button.setDebounceTime(40);
voldow_button.setButtonStateFunction(capStateHandler4);
voldow_button.setClickHandler(voldow_click);
voldow_button.begin(VIRTUAL_PIN);

}

/////////////////////////////////////////////////////////////////

void loop() {
menu_button.loop();
eq_button.loop();
volup_button.loop();
voldow_button.loop();
}

/////////////////////////////////////////////////////////////////
void click(Button2& btn) {
Serial.println("menu click\n");
}

// long click
void longClick(Button2 &btn) {
unsigned int time = btn.wasPressedFor();
if (time > 1000) {
Serial.println("long click\n");
}
}

void eq_click(Button2& btn) {
Serial.println("eq click\n");
}

void volup_click(Button2& btn) {
Serial.println("volup click\n");
}

void voldow_click(Button2& btn) {
Serial.println("voldow click\n");
}

/////////////////////////////////////////////////////////////////
#endif
/////////////////////////////////////////////////////////////////


setStateHandler Functions

Hi,

is there a way to call functions with values like:

button1.setButtonStateFunction(buttonstate(i)).

So i can use one state function for different buttons?

All the best and love
Adrian

Partial Reverse

It seems like the isPressed() method is somehow reversed..

When all is behaving as it should - click working etc.. the status of isPressed is 0 when the button is pressed and 1 when the button is released?

Is that by intension or is it a bug?

I have this code running on a Wemos ESP8266 Mini D1 Lite what what is the reference for isPressed - imo it should return 1 if the button is pressed, and 0 if released

I have tried to init the button with activeLow = false also, but still i always endup getting the "reverse" of what i expect in the isPressed() method..

#include <Arduino.h>
#include <Blink.h>

// #define DEBOUNCE_MS 100
#include <Button2.h>

// int LED_PIN = D8;
int LED_PIN = LED_BUILTIN;
int BTN_PIN = D1;

unsigned long lastUpdate = millis();

Button2 btn(BTN_PIN);

void statusUpdate()
{
  if ((millis() - lastUpdate) > 1000)
  {
    bool btnPressed = btn.isPressed();
    lastUpdate = millis();
    if (btnPressed == 0)
    {
      Serial.println("Pressed");
      Serial.print("Library: ");
      Serial.println(btnPressed);
      Serial.print("Digital Read: ");
      Serial.println(digitalRead(BTN_PIN));
    }
    else
    {
      Serial.println("Released");
      Serial.print("Library: ");
      Serial.println(btnPressed);
      Serial.print("Digital Read: ");
      Serial.println(digitalRead(BTN_PIN));
    }
  }
}

void btnClick(Button2& btn) {
    Serial.println("Click\n");
}

void btnTap(Button2 &btn)
{
  Serial.println("Tap\n");
  digitalWrite(LED_PIN, LOW);
  delay(100);
  digitalWrite(LED_PIN, HIGH);
  delay(100);
}

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(100);
  Serial.println("Startup!");
  delay(50);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  btn.setTapHandler(btnTap);
  btn.setClickHandler(btnClick);
}

void loop()
{
  btn.loop();
  statusUpdate();
}

2.3.x breaks default implementation?

Hi!

Sry if the title might be confusing, but so is the issue I experience.

I have reduced my button code to the core to be able to reproduce it.
This code seems to be working fine on version 2.2.4 of the library, but doesn't recognise my button button anymore from 2.3.0 and 2.3.1

#include <Arduino.h>
#include <Button2.h>

#define BUTTON_PIN 19

Button2 button;

void setup() {
  Serial.begin(115200);
  Serial.println("Starting Setup");

  button.begin(BUTTON_PIN);

}

void loop() {
  button.loop();

  clickType buttonState = button.read();

  if (buttonState != clickType::empty) {
    Serial.println("Button State not empty");
  }
}

Because I first thought my button broke I even tried to just short PIN and GND. But I experienced the same behaviour with shorting.

Help or explanation would be highly appreciated.

detection of long presses does not work properly inside of an interupt timer

FYI, as you predicted when using this library inside an interrupt timer on an esp32, it seems to fail to detect long clicks. Every click, long or short, irregardless of .setLongClickTime() is detected as a long click. I haven't delved into why this behaviour is being exhibited but was able to create a quick work around by capturing the start and stop time of the button presses / release within my own application.

Here is a snippet:

#define MODE_BUTTON  35

Button2 buttonMode;
hw_timer_t *mButtonTimer = NULL;

void IRAM_ATTR buttonTimer()
{
  // process buttons
  buttonMode.loop();
}

setup() 
{
  mButtonTimer = timerBegin(0, 80, true);
  timerAttachInterrupt(mButtonTimer, &buttonTimer, true);
  timerAlarmWrite(mButtonTimer, 10000, true); // every 0.1 seconds
  timerAlarmEnable(mButtonTimer);

  buttonMode.begin(MODE_BUTTON, INPUT, false);
  buttonMode.setLongClickHandler(longModeClickStart);
  buttonMode.setLongClickDetectedHandler(longModeClickStop);
}


long modeStart;

void longModeClickStart(Button2 &btn)
{
  modeStart = micros();
}

void longModeClickStop(Button2 &btn)
{
  int secondsSinceLast = round((micros() - modeStart) / 1000000);
  Serial.print("Seconds since last mode press: ");
  Serial.println(secondsSinceLast);
  if (secondsSinceLast > 20)
  {
   Serial.println("doing something after 20 seconds");
  }
}

Button2 Class has no member getAttachPin

I am referencing a sketch that uses Button2 and I was pointed to this repo, however there is an error I am getting about getAttachPin, in searching your code I see that it in fact doesn't appear.

I have found several sketches that reference this non-existant class member:

I am using your current master as of this date (1.5.3)

I am not sure where the error is, I can't see any member that returns a pin from the class. Is this something that other parties have created as an extension to your class? It's funny that several sketches refer to it

SerialBT issue

Hi!
I'm working on esp32 and I need SerialBT lib AND button2.. button2 work great if I comment out SerialBT command in sketch.
As soon as I uncomment SerialBT command, button2 refuse to work. SerialBT is working.

There's no delay is code.

Suggestion to add options for Led Buttons

Would be nice to have option to control button with LED, option to set pin for button LED and have function to turn it on/off, remember state, different led flash patterns for different press types etc.
Maybe make inheriting class from Button2, for example Button2Led...
ledbutton

Filtering out Single press while waiting for the Long Press

I've got a button, with setLongClickHandler, and setPressedHandler
When I press button shortly, my PressedHandler works fine. But it also triggers when I do LongPress. So, I get an event just once I pressed the button, and another event in few ms (long press detected)

So the question is - how to filter out the Short Press events when waiting for the LongPress?

Long Press Also Executes Press

My understanding is that the library would distinguish between a click and a hold, not perform both actions when the button is held, which is what is happening.

Decalring SetHandler time

Hi I am trying to use your library for my code, everything seems to be working on compile. However, I am getting an error code saying src\main.cpp: In function 'void setup()':
src\main.cpp:89:27: error: 'click' was not declared in this scope
buttonA.setClickHandler(click);

I am using the multiple buttons part from your code

clear assigned functions

In some cases it would be helpful to clear all assigned functions and variables.
Example: menu handling where after a click new functions must be assigned, but all older have to be cleared. It can be done right now by manually assigning NULL to all of them, but a simple clear function would solve it.
Another option to delete buttons and create new ones as this is done when an instance is created. But that needs more resources. Any suggestions?

Disable double/triple click detection

I'w writing a BT BLE keyboard to remotely control a machine via keyboard shortcuts, the most used keys are the arrows, and sometimes you click these a lot to get to the exact position.
Is there a way to disable repetitive click to be detected as double/triple clicks?
I can hack this by duplicating the detection and issuing double/triple the amount of keyboard taps on the respective handlers, but I guess a DEFINE would be far more elegant. Same for long press would be the icing in the cake :)

Thanks!

Long click retriggerable stopped working in a recent update.

I don't know which version had this happen, but something changed in the long click and retriggerable features recently, and now my "held down" buttons don't work, though they worked with an earlier version of the library. Can you check to see if any of your recent updates caused this? Is this a known issue?

Attached is my code. Perhaps you can glean something from it?

Master Bedroom LEDs.zip

Question/FMR: Are buttons interrupt enabled?

Hello, I have a need for a button that can detect a press while in a do/while loop. The application is for a rock tumbler. In my code, I calculate a runtime using a 100k Pot, then use some math to calculate a total number of rotations that need to be executed. The program then hands off to a loop that commits one rotation and then loops for the number of calculated passes.

My code process is more or less like this

setup()
{
    button.setLongClickHandler(longClick);
    button.setDoubleClickHandler(doubleClick);
    button.setClickHandler(click);
}

void longClick(Button2& btn) 
{
        Log("long Click, Start running\n");
        DrawSmallText(szStartRunning);

        b_RunningState = !b_RunningState;
        if (b_RunningState)
        {
           	StartRunning();
        }
 }

void doubleClick(Button2& btn) 
{
    Log("double click detected, change rotation count\n");
    long lHours = 0;
    char buf[20];

    DrawSmallText(szDialHelp);

	    b_SettingRunTime = !b_SettingRunTime;

        //This is extremely ugly, I need to come up with a better way to handle getting the value and present it.
    do 
    {
	    pot_val = analogRead(POT_PIN);

	    lHours = map(pot_val, 0, 1023, 5, 245);
	    sprintf(buf, "Run %u Hrs", lHours);
	
	    DrawSmallText(String(buf));
	
     } while (b_SettingRunTime);

    //Set the total number of rotations from the calculation macro
    Rotations = ROTATE(lHours);
 }

//Handle the clicks, to set the event flags, (this assumes multi threading which doesnt really exist.
//    so I need to re-evaluate how to handle this part
 void click(Button2& btn) 
  {
    Log("click, do something...\n");

    if(b_SettingRunTime)
	    b_SettingRunTime = false;

    if(b_SettingRPM)
	    b_SettingRPM = false;
	
     if(b_RunningState)
	    b_RunningState = false;
  }

void StartRunning()
{

    digitalWrite(DIR_PIN, HIGH);	//Turn stepper clockwise
    digitalWrite(LED_RUNNING, HIGH);   // turn on the running led
	
    do
    {
	// Spin motor for 1 rotation
	for(int x = 0; x < stepsPerRevolution; x++)
	{
		digitalWrite(STEP_PIN, HIGH);
		delayMicroseconds(stepDelay);
		digitalWrite(STEP_PIN, LOW);
		delayMicroseconds(stepDelay);
	}
    }while (Rotations-- > 0);
    digitalWrite(LED_RUNNING, LOW);    // turn the LED off by making the voltage LOW
}

What I want to do is detect clicks from within the StartRunning(), clicks should change the display message to show remaining time running, and a long click to stop the motor.

I can do this with making my own interrupt, but I wasn't sure if I should do that, or add a detection in the loop for a DigitalRead, or if there were a way to interrupt to detect presses inside the loop using one of your apis?

Any advice or ideas would be most appreciated!

Cheers!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.