4bdcdd0ec12bed113df9f8379e9c4b63bb1df07f
[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     
23     # Only return after n(retries) consistent results, although not necessarily
24     # in order. This means we poll at least (retries) and up to (retries ** 2) times.
25     # This is mtearle's original code. No idea if it's the Right Thing.
26     while True:
27         try:
28             wfh.write(test_string)
29             wfh.flush()
30         except:
31             results['error'] -= 1
32             if results['error'] == 0: return -1
33             continue
34         rr, wr, er = select([rfh], [], [], 3.0)
35         if rfh not in rr:
36             results['open'] -= 1
37             if results['open'] == 0: return 1
38             continue
39         recv = rfh.read(len(test_string))
40         if recv <> test_string:
41             results['error'] -= 1
42             if results['error'] == 0: return -1
43             continue
44         results['closed'] -= 1
45         if results['closed'] == 0: return 0
46
47 class Door(dbus.service.Object):
48     
49     def __init__(self, doorname, bus):
50         self.interval = 10 # seconds
51         self.service = doorname
52         self.status = -1
53         self.retries = 3
54         if 'pir' in self.service:
55             self.retries = 1
56         
57         # set up D-BUS service name
58         object_path = '/au/asn/ucc/doors/%s' % doorname
59         dbus.service.Object.__init__(self, bus, object_path)
60         
61         # get initial state in a new thread
62         self.timeout = Timer(0, self.poll)
63         # daemon threads will be killed when the mainloop exits
64         # the timeout threads will inherit this value
65         self.timeout.setDaemon(True)
66         self.timeout.start()
67     
68     def poll(self):
69         try:
70             newstatus = check_LAT_service(self.service, self.retries)
71         except:
72             newstatus = -1
73         
74         if newstatus != self.status:
75             syslog.syslog(142, "status changed detected for %s; status: %i, newstatus: %i" % (self.service, self.status, newstatus))
76             self.status = newstatus
77             # emit signal
78             self.status_changed(newstatus)
79             # back off if broken
80             self.interval = [10,10,20][newstatus]
81         
82         # set up timeout again
83         self.timeout = Timer(self.interval, self.poll)
84         self.timeout.start()
85     
86     @dbus.service.signal('au.asn.ucc.DoorInterface', signature='n')
87     def status_changed(self, newstatus):
88         pass
89     
90     @dbus.service.method('au.asn.ucc.DoorInterface', in_signature='',
91                          out_signature='n')
92     def get_status(self):
93         return self.status
94
95 if __name__ == '__main__':
96     gobject.threads_init()
97     doors = ('uccdoor', 'unisfadoor', 'chdoor', 'mrdoor', 'uccpir')
98     
99     from dbus.mainloop.glib import DBusGMainLoop
100     DBusGMainLoop(set_as_default=True)
101     # get on the bus
102     system_bus = dbus.SystemBus()
103     system_bus.request_name('au.asn.ucc.DoorServer')
104     
105     door_objects = []
106
107     for door in doors:
108         door_objects.append(Door(door, system_bus))
109
110     # engage!
111     loop = gobject.MainLoop()
112     try:
113         loop.run()
114     except KeyboardInterrupt:
115         loop.quit()
116     except:
117         pass

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