Version 0.2 (includes log and icon \o/)
[saartuer.git] / ringd
diff --git a/ringd b/ringd
index 812043adb4ea914ca15a21c9c8ed70a7dc21ec28..b6a27f940ea9fe5ebccd23a77ba07e439bfce699 100755 (executable)
--- a/ringd
+++ b/ringd
@@ -1,36 +1,87 @@
 #!/usr/bin/python3
 #!/usr/bin/python3
-import time, socket
+import time, socket, atexit
+import queue, threading, select
+from libtuer import log, ThreadFunction
 import RPi.GPIO as GPIO
 import RPi.GPIO as GPIO
+GPIO.setmode(GPIO.BOARD)
+atexit.register(GPIO.cleanup)
 
 tuerSock = "/run/tuer.sock"
 
 tuerSock = "/run/tuer.sock"
-
 ringPin = 18
 
 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._callback = ThreadFunction(self.callback)
+               self.stop = self._callback.stop
+       
+       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._callback(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
 
 
-
-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')
                # 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()
                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.stop()