use local1.info as it's ridiculously spammy
[uccdoor.git] / server.py
1 #! /usr/bin/env python
2 # UCC Door Server - hardware interface server
3 # reads status of reed switches and provides a D-BUS interface to read them
4 # David Adam <zanchey@ucc.gu.uwa.edu.au>
5 # LAT interface based on work by Mark Tearle <mtearle@ucc.gu.uwa.edu.au>
6 # Released under an MIT-style license; see COPYING for details.
7
8 # statuses: 1 means open circuit, 0 means closed circuit, -1 means error
9
10 import syslog
11 import dbus, dbus.service
12 import gobject
13 from LATClient import LATClient
14 from select import select
15 from threading import Timer
16
17 def check_LAT_service(servicename, retries=3):
18     latclient = LATClient(service=servicename.upper())
19     rfh, wfh = latclient.get_fh()
20     results = {'error': retries, 'closed': retries, 'open': retries}
21     test_string = "got wombles?"
22     syslog.syslog(142, "start check_LAT_service:" + servicename)
23     
24     # Only return after n(retries) consistent results, although not necessarily
25     # in order. This means we poll at least (retries) and up to (retries ** 2) times.
26     # This is mtearle's original code. No idea if it's the Right Thing.
27     while True:
28         syslog.syslog(142, "running c_L_s loop:" + servicename)
29         try:
30             wfh.write(test_string)
31             wfh.flush()
32         except:
33             results['error'] -= 1
34             if results['error'] == 0: return -1
35             syslog.syslog(142, "c_L_s write error:" + servicename)
36             continue
37         syslog.syslog(142, "c_Ls written data to " + servicename)
38         rr, wr, er = select([rfh], [], [], 3.0)
39         if rfh not in rr:
40             results['open'] -= 1
41             if results['open'] == 0: return 1
42             syslog.syslog(142, "c_L_s open: " + servicename)
43             continue
44         syslog.syslog(142, "c_L_s select() succeeded: " + servicename)
45         recv = rfh.read(len(test_string))
46         syslog.syslog(142, "c_L_s read() succeeded: " + servicename)
47         if recv <> test_string:
48             syslog.syslog(142, "c_L_s not the data we sent " + servicename)
49             results['error'] -= 1
50             if results['error'] == 0: return -1
51             continue
52         results['closed'] -= 1
53         syslog.syslog(142, "c_L_s closed " + servicename)
54         if results['closed'] == 0: return 0
55
56 class Door(dbus.service.Object):
57     
58     def __init__(self, doorname, bus):
59         self.interval = 10 # seconds
60         self.service = doorname
61         self.status = -1
62         self.retries = 3
63         if 'pir' in self.service:
64             self.retries = 1
65         
66         # set up D-BUS service name
67         object_path = '/au/asn/ucc/doors/%s' % doorname
68         dbus.service.Object.__init__(self, bus, object_path)
69         
70         # get initial state in a new thread
71         self.timeout = Timer(0, self.poll)
72         # daemon threads will be killed when the mainloop exits
73         # the timeout threads will inherit this value
74         self.timeout.setDaemon(True)
75         self.timeout.start()
76     
77     def poll(self):
78         try:
79             newstatus = check_LAT_service(self.service, self.retries)
80         except:
81             newstatus = -1
82         
83         if newstatus != self.status:
84             self.status = newstatus
85             # emit signal
86             self.status_changed(newstatus)
87         
88         # set up timeout again
89         self.timeout = Timer(self.interval, self.poll)
90         self.timeout.start()
91     
92     @dbus.service.signal('au.asn.ucc.DoorInterface', signature='n')
93     def status_changed(self, newstatus):
94         pass
95     
96     @dbus.service.method('au.asn.ucc.DoorInterface', in_signature='',
97                          out_signature='n')
98     def get_status(self):
99         return self.status
100
101 if __name__ == '__main__':
102     gobject.threads_init()
103     doors = ('uccdoor', 'unisfadoor', 'chdoor', 'mrdoor', 'uccpir')
104     
105     from dbus.mainloop.glib import DBusGMainLoop
106     DBusGMainLoop(set_as_default=True)
107     # get on the bus
108     system_bus = dbus.SystemBus()
109     system_bus.request_name('au.asn.ucc.DoorServer')
110     
111     door_objects = []
112
113     for door in doors:
114         door_objects.append(Door(door, system_bus))
115
116     # engage!
117     loop = gobject.MainLoop()
118     try:
119         loop.run()
120     except KeyboardInterrupt:
121         loop.quit()
122     except:
123         pass

UCC git Repository :: git.ucc.asn.au