From 3f4b39eb1ce246b3426a7d880a021ba8ea92dfde Mon Sep 17 00:00:00 2001 From: Neradoc Date: Fri, 11 Mar 2022 17:47:30 +0100 Subject: [PATCH 1/3] fix the button class doing some double edge detection and docs --- adafruit_debouncer.py | 52 +++++++++++++++++++++---------------- examples/debouncer_multi.py | 5 ++-- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/adafruit_debouncer.py b/adafruit_debouncer.py index 5182e5f..36de350 100644 --- a/adafruit_debouncer.py +++ b/adafruit_debouncer.py @@ -133,7 +133,16 @@ def current_duration(self): class Button(Debouncer): - """Debounce counter""" + """ + Debounce counter. Counts multiple short presses (double click, triple click, etc.) + Reports long presses. + + :param DigitalInOut/function pin: the DigitalIO or function to debounce. + :param int short_duration_ms: the maximum length of a short press in milliseconds. + :param int long_duration_ms: the minimum length of a long press in milliseconds. + :param bool active_down: True if a `False` value for the predicate represents + "pressed" (like pull up buttons). + """ def __init__( self, @@ -150,29 +159,28 @@ def __init__( self.short_counter = 0 self.short_to_show = 0 self.long_registered = False - self.long_showed = False + self.long_to_show = False super().__init__(pin, **kwargs) - def _pushed(self): - return (self.active_down and super().fell) or ( - not self.active_down and super().rose - ) + @property + def pressed(self): + """Return whether the button was pressed or not at the last update.""" + return (self.active_down and self.fell) or (not self.active_down and self.rose) - def _released(self): - return (self.active_down and super().rose) or ( - not self.active_down and super().fell - ) + @property + def released(self): + """Return whether the button was release or not at the last update.""" + return (self.active_down and self.rose) or (not self.active_down and self.fell) def update(self, new_state=None): super().update(new_state) - if self._pushed(): + if self.pressed: self.last_change_ms = ticks_ms() self.short_counter = self.short_counter + 1 - elif self._released(): + elif self.released: self.last_change_ms = ticks_ms() if self.long_registered: self.long_registered = False - self.long_showed = False else: duration = ticks_diff(ticks_ms(), self.last_change_ms) if ( @@ -181,6 +189,7 @@ def update(self, new_state=None): and duration > self.long_duration_ms ): self.long_registered = True + self.long_to_show = True self.short_to_show = self.short_counter - 1 self.short_counter = 0 elif ( @@ -190,18 +199,17 @@ def update(self, new_state=None): ): self.short_to_show = self.short_counter self.short_counter = 0 + else: + self.long_to_show = False + self.short_to_show = 0 @property def short_count(self): - """Return the number of short press""" - ret = self.short_to_show - self.short_to_show = 0 - return ret + """Return the number of short press if a series of short presses has + ended at the last update.""" + return self.short_to_show @property def long_press(self): - """Return whether long press has occured""" - if self.long_registered and not self.long_showed: - self.long_showed = True - return True - return False + """Return whether a long press has occured at the last update.""" + return self.long_to_show diff --git a/examples/debouncer_multi.py b/examples/debouncer_multi.py index 976cd84..d5f162f 100644 --- a/examples/debouncer_multi.py +++ b/examples/debouncer_multi.py @@ -16,6 +16,5 @@ switch.update() if switch.long_press: print("long") - count = switch.short_count - if count != 0: - print("count=", count) + if switch.short_count != 0: + print("count=", switch.short_count) From c6b924e7e10439aec29eab31aa004db8b61f8db8 Mon Sep 17 00:00:00 2001 From: Neradoc Date: Fri, 11 Mar 2022 18:25:48 +0100 Subject: [PATCH 2/3] change active_down to value_when_pressed --- adafruit_debouncer.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/adafruit_debouncer.py b/adafruit_debouncer.py index 36de350..30d5c93 100644 --- a/adafruit_debouncer.py +++ b/adafruit_debouncer.py @@ -140,8 +140,8 @@ class Button(Debouncer): :param DigitalInOut/function pin: the DigitalIO or function to debounce. :param int short_duration_ms: the maximum length of a short press in milliseconds. :param int long_duration_ms: the minimum length of a long press in milliseconds. - :param bool active_down: True if a `False` value for the predicate represents - "pressed" (like pull up buttons). + :param bool value_when_pressed: the value of the predicate when the button is + pressed. Defaults to False (pull up buttons are common). """ def __init__( @@ -149,12 +149,12 @@ def __init__( pin, short_duration_ms=200, long_duration_ms=500, - active_down=True, + value_when_pressed=False, **kwargs ): self.short_duration_ms = short_duration_ms self.long_duration_ms = long_duration_ms - self.active_down = active_down + self.value_when_pressed = value_when_pressed self.last_change_ms = ticks_ms() self.short_counter = 0 self.short_to_show = 0 @@ -165,12 +165,16 @@ def __init__( @property def pressed(self): """Return whether the button was pressed or not at the last update.""" - return (self.active_down and self.fell) or (not self.active_down and self.rose) + return (self.value_when_pressed and self.rose) or ( + not self.value_when_pressed and self.fell + ) @property def released(self): """Return whether the button was release or not at the last update.""" - return (self.active_down and self.rose) or (not self.active_down and self.fell) + return (self.value_when_pressed and self.fell) or ( + not self.value_when_pressed and self.rose + ) def update(self, new_state=None): super().update(new_state) @@ -185,7 +189,7 @@ def update(self, new_state=None): duration = ticks_diff(ticks_ms(), self.last_change_ms) if ( not self.long_registered - and self.value != self.active_down + and self.value == self.value_when_pressed and duration > self.long_duration_ms ): self.long_registered = True @@ -194,7 +198,7 @@ def update(self, new_state=None): self.short_counter = 0 elif ( self.short_counter > 0 - and self.value == self.active_down + and self.value != self.value_when_pressed and duration > self.short_duration_ms ): self.short_to_show = self.short_counter From a2508e8b032176695fa44ad73e914d5ee44927d7 Mon Sep 17 00:00:00 2001 From: Neradoc Date: Fri, 11 Mar 2022 18:33:48 +0100 Subject: [PATCH 3/3] fix doc and gitignore, add to the example --- .gitignore | 15 ++++++++++++++- adafruit_debouncer.py | 8 +++++--- examples/debouncer_multi.py | 6 ++++-- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 7926313..2c6ddfd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,18 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense *.mpy +.idea +__pycache__ +_build +*.pyc +.env +.python-version +build*/ +bundles +*.DS_Store +.eggs +dist +**/*.egg-info +.vscode diff --git a/adafruit_debouncer.py b/adafruit_debouncer.py index 30d5c93..868a217 100644 --- a/adafruit_debouncer.py +++ b/adafruit_debouncer.py @@ -134,14 +134,16 @@ def current_duration(self): class Button(Debouncer): """ - Debounce counter. Counts multiple short presses (double click, triple click, etc.) - Reports long presses. + Debouncer for buttons. Reports ``pressed`` and ``released`` for the button state. + Counts multiple short presses, allowing to detect double clicks, triple clicks, etc. + Reports long presses separately. A long press can immediately follow multiple clicks, + in which case the long click will be reported in the same update as the short clicks. :param DigitalInOut/function pin: the DigitalIO or function to debounce. :param int short_duration_ms: the maximum length of a short press in milliseconds. :param int long_duration_ms: the minimum length of a long press in milliseconds. :param bool value_when_pressed: the value of the predicate when the button is - pressed. Defaults to False (pull up buttons are common). + pressed. Defaults to False (for pull up buttons). """ def __init__( diff --git a/examples/debouncer_multi.py b/examples/debouncer_multi.py index d5f162f..424ca78 100644 --- a/examples/debouncer_multi.py +++ b/examples/debouncer_multi.py @@ -15,6 +15,8 @@ while True: switch.update() if switch.long_press: - print("long") + print("Long Press") if switch.short_count != 0: - print("count=", switch.short_count) + print("Short Press Count =", switch.short_count) + if switch.long_press and switch.short_count == 1: + print("That's a long double press !")