]>
vault307.fbx.one Git - ir_remote.git/blob - primitives/pushbutton.py
3 # Copyright (c) 2018-2022 Peter Hinch
4 # Released under the MIT License (MIT) - see LICENSE file
6 import uasyncio
as asyncio
8 from . import launch
, Delay_ms
11 from machine
import TouchPad
21 def __init__(self
, pin
, suppress
=False, sense
=None):
22 self
._pin
= pin
# Initialise for input
24 self
._dblpend
= False # Doubleclick waiting for 2nd click
25 self
._dblran
= False # Doubleclick executed user function
29 self
._ld
= False # Delay_ms instance for long press
30 self
._dd
= False # Ditto for doubleclick
31 # Convert from electrical to logical value
32 self
._sense
= pin
.value() if sense
is None else sense
33 self
._state
= self
.rawstate() # Initial state
34 self
._run
= asyncio
.create_task(self
._go
()) # Thread runs forever
38 self
._check
(self
.rawstate())
39 # Ignore state changes until switch has settled. Also avoid hogging CPU.
40 # See https://github.com/peterhinch/micropython-async/issues/69
41 await asyncio
.sleep_ms(Pushbutton
.debounce_ms
)
43 def _check(self
, state
):
44 if state
== self
._state
:
46 # State has changed: act on it now.
48 if state
: # Button pressed: launch pressed func
50 launch(self
._tf
, self
._ta
)
51 if self
._ld
: # There's a long func: start long press delay
52 self
._ld
.trigger(Pushbutton
.long_press_ms
)
54 if self
._dd
(): # Second click: timer running
57 self
._dblran
= True # Prevent suppressed launch on release
58 launch(self
._df
, self
._da
)
60 # First click: start doubleclick timer
61 self
._dd
.trigger(Pushbutton
.double_click_ms
)
62 self
._dblpend
= True # Prevent suppressed launch on release
63 else: # Button release. Is there a release func?
67 # If long delay exists, is running and doubleclick status is OK
68 if not self
._dblpend
and not self
._dblran
:
69 if (d
and d()) or not d
:
70 launch(self
._ff
, self
._fa
)
72 launch(self
._ff
, self
._fa
)
74 self
._ld
.stop() # Avoid interpreting a second click as a long push
77 def _ddto(self
): # Doubleclick timeout: no doubleclick occurred
79 if self
._supp
and not self
._state
:
80 if not self
._ld
or (self
._ld
and not self
._ld
()):
81 launch(self
._ff
, self
._fa
)
84 def press_func(self
, func
=False, args
=()):
86 self
.press
= asyncio
.Event()
87 self
._tf
= self
.press
.set if func
is None else func
90 def release_func(self
, func
=False, args
=()):
92 self
.release
= asyncio
.Event()
93 self
._ff
= self
.release
.set if func
is None else func
96 def double_func(self
, func
=False, args
=()):
98 self
.double
= asyncio
.Event()
99 func
= self
.double
.set
102 if func
: # If double timer already in place, leave it
104 self
._dd
= Delay_ms(self
._ddto
)
106 self
._dd
= False # Clearing down double func
108 def long_func(self
, func
=False, args
=()):
110 self
.long = asyncio
.Event()
114 self
._ld
.callback(func
, args
)
116 self
._ld
= Delay_ms(func
, args
)
120 # Current non-debounced logical button state: True == pressed
122 return bool(self
._pin
() ^ self
._sense
)
124 # Current debounced state of button (True == pressed)
132 class ESP32Touch(Pushbutton
):
133 thresh
= (80 << 8) // 100
136 def threshold(cls
, val
):
137 if not (isinstance(val
, int) and 0 < val
< 100):
138 raise ValueError("Threshold must be in range 1-99")
139 cls
.thresh
= (val
<< 8) // 100
141 def __init__(self
, pin
, suppress
=False):
142 self
._thresh
= 0 # Detection threshold
145 self
._pad
= TouchPad(pin
)
147 raise ValueError(pin
) # Let's have a bit of information :)
148 super().__init
__(pin
, suppress
, False)
150 # Current logical button state: True == touched
152 rv
= self
._pad
.read() # ~220μs
153 if rv
> self
._rawval
: # Either initialisation or pad was touched
154 self
._rawval
= rv
# when initialised and has now been released
155 self
._thresh
= (rv
* ESP32Touch
.thresh
) >> 8
156 return False # Untouched
157 return rv
< self
._thresh