58148045d34ad8b624244fc863576b6b3f61ae89
[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             syslog.syslog(142, "c_L_s write error:" + servicename)
35             if results['error'] == 0: return -1
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         syslog.syslog(142, "status, newstatus for %s is %i, %i" % (self.service, self.status, newstatus))
84         if newstatus != self.status:
85             syslog.syslog(142, "status changed detected for  %s" % self.service)
86             self.status = newstatus
87             # emit signal
88             self.status_changed(newstatus)
89         
90         # set up timeout again
91         self.timeout = Timer(self.interval, self.poll)
92         self.timeout.start()
93     
94     @dbus.service.signal('au.asn.ucc.DoorInterface', signature='n')
95     def status_changed(self, newstatus):
96         pass
97     
98     @dbus.service.method('au.asn.ucc.DoorInterface', in_signature='',
99                          out_signature='n')
100     def get_status(self):
101         return self.status
102
103 if __name__ == '__main__':
104     gobject.threads_init()
105     doors = ('uccdoor', 'unisfadoor', 'chdoor', 'mrdoor', 'uccpir')
106     
107     from dbus.mainloop.glib import DBusGMainLoop
108     DBusGMainLoop(set_as_default=True)
109     # get on the bus
110     system_bus = dbus.SystemBus()
111     system_bus.request_name('au.asn.ucc.DoorServer')
112     
113     door_objects = []
114
115     for door in doors:
116         door_objects.append(Door(door, system_bus))
117
118     # engage!
119     loop = gobject.MainLoop()
120     try:
121         loop.run()
122     except KeyboardInterrupt:
123         loop.quit()
124     except:
125         pass

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