Version 0.2 (includes log and icon \o/)
[saartuer.git] / ringd
1 #!/usr/bin/python3
2 import time, socket, atexit
3 import queue, threading, select
4 from libtuer import log, ThreadFunction
5 import RPi.GPIO as GPIO
6 GPIO.setmode(GPIO.BOARD)
7 atexit.register(GPIO.cleanup)
8
9 tuerSock = "/run/tuer.sock"
10 ringPin = 18
11
12
13 # Main classes
14 class PinWatcher():
15         def __init__(self, pin, histlen):
16                 GPIO.setup(pin, GPIO.IN)
17                 assert histlen > 1 # otherwise our logic goes nuts...
18                 self._pin = pin
19                 self._histlen = histlen
20                 # state change detection
21                 self._state = None
22                 self._newstate = None # != None iff we are currently seeing a state change
23                 self._newstatelen = 0 # only valid if newstate != None
24                 # start state change handler thread
25                 self._callback = ThreadFunction(self.callback)
26                 self.stop = self._callback.stop
27         
28         def read(self):
29                 curstate = GPIO.input(self._pin)
30                 assert curstate in (0, 1)
31                 if curstate != self._state:
32                         # the state is about to change
33                         if curstate == self._newstate:
34                                 # we already saw this new state
35                                 self._newstatelen += 1
36                                 if self._newstatelen >= self._histlen:
37                                         self._callback(self._state, curstate) # send stuff to the other thread
38                                         self._state = curstate
39                                         self._newstate = None
40                         else:
41                                 # now check for how long we see this new state
42                                 self._newstate = curstate
43                                 self._newstatelen = 1
44                 else:
45                         # old state is preserved
46                         self._newstate = None
47
48 class RingWatcher(PinWatcher):
49         def __init__(self):
50                 super().__init__(ringPin, 2)
51                 self.last1Event = None
52         
53         def callback(self, oldstate, newstate):
54                 if oldstate is None:
55                         return # ignore the very first state change
56                 # now (oldstate, newstate) is either (0, 1) or (1, 0)
57                 if newstate:
58                         self.last1Event = time.time()
59                 elif self.last1Event is not None:
60                         # how long was this pressed?
61                         timePressed = time.time() - self.last1Event
62                         log("Ring button pressed for",timePressed)
63                         if timePressed >= 1.5 and timePressed <= 3:
64                                 self.buzz()
65         
66         def buzz(self):
67                 log("Opening door")
68                 # talk with tuerd
69                 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
70                 s.connect(tuerSock)
71                 s.send(b'buzz')
72                 s.close()
73
74 # MAIN PROGRAM
75 pins = [
76         RingWatcher(),
77 ]
78
79 try:
80         log("entering loop")
81         while True:
82                 for pin in pins:
83                         pin.read()
84                 time.sleep(0.02)
85 except KeyboardInterrupt:
86         for pin in pins:
87                 pin.stop()