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

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