X-Git-Url: https://git.ralfj.de/saartuer.git/blobdiff_plain/6e7d90d419547705cb125adc7fe3626d9dc0fd49..83d646a505bed8c75eef15855da7046e5854106d:/ringd?ds=inline diff --git a/ringd b/ringd index 812043a..201322f 100755 --- a/ringd +++ b/ringd @@ -1,36 +1,99 @@ #!/usr/bin/python3 -import time, socket +import time, socket, atexit +import queue, threading, select +from libtuer import log import RPi.GPIO as GPIO +GPIO.setmode(GPIO.BOARD) +atexit.register(GPIO.cleanup) tuerSock = "/run/tuer.sock" - ringPin = 18 -GPIO.setmode(GPIO.BOARD) -GPIO.setup(ringPin, GPIO.IN) - -lastEvent = 0 - +# Main classes +class PinWatcher(): + def __init__(self, pin, histlen): + GPIO.setup(pin, GPIO.IN) + assert histlen > 1 # otherwise our logic goes nuts... + self._pin = pin + self._histlen = histlen + # state change detection + self._state = None + self._newstate = None # != None iff we are currently seeing a state change + self._newstatelen = 0 # only valid if newstate != None + # start state change handler thread + self._q = queue.Queue() + self._t = threading.Thread(target=self.queue_consumer) + self._t.start() + + def queue_consumer(self): + while True: + el = self._q.get() + if el is None: return # we are supposed to terminate + # handle the state change + (oldstate, newstate) = el + self.callback(oldstate, newstate) + + def read(self): + curstate = GPIO.input(self._pin) + assert curstate in (0, 1) + if curstate != self._state: + # the state is about to change + if curstate == self._newstate: + # we already saw this new state + self._newstatelen += 1 + if self._newstatelen >= self._histlen: + self._q.put((self._state, curstate)) # send stuff to the other thread + self._state = curstate + self._newstate = None + else: + # now check for how long we see this new state + self._newstate = curstate + self._newstatelen = 1 + else: + # old state is preserved + self._newstate = None + + def quit(self): + self._q.put(None) + self._t.join() -while True: - GPIO.wait_for_edge(ringPin, GPIO.BOTH) - # measure time since event - now = time.time() - timePassed = now-lastEvent - print("Time between events %f" % timePassed) - # remember, remember - lastEvent = now - # action to be taken? - if timePassed >= 1.5 and timePassed <= 3: - print("Opening door") +class RingWatcher(PinWatcher): + def __init__(self): + super().__init__(ringPin, 2) + self.last1Event = None + + def callback(self, oldstate, newstate): + if oldstate is None: + return # ignore the very first state change + # now (oldstate, newstate) is either (0, 1) or (1, 0) + if newstate: + self.last1Event = time.time() + elif self.last1Event is not None: + # how long was this pressed? + timePressed = time.time() - self.last1Event + log("Ring button pressed for",timePressed) + if timePressed >= 1.5 and timePressed <= 3: + self.buzz() + + def buzz(self): + log("Opening door") # talk with tuerd s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.connect(tuerSock) s.send(b'buzz') - data = s.recv(4) s.close() - print("...done") - if data != b'1': - print("Received unexpected answer %s" % str(data)) -GPIO.cleanup() +# MAIN PROGRAM +pins = [ + RingWatcher(), +] + +try: + log("entering loop") + while True: + for pin in pins: + pin.read() + time.sleep(0.02) +except KeyboardInterrupt: + for pin in pins: + pin.quit()