Mercurial > code > home > repos > light9
annotate light8/dmxserver.py @ 118:2c25a69c084d
now tracks update frequencies of the server and each client
now tracks update frequencies of the server and each client
now forgets clients that haven't submitted a value in 5sec
refactored sendlevels into a few methods
new cmdline option --fast-updates to dump every DMX transmission to the console
author | drewp |
---|---|
date | Fri, 13 Jun 2003 13:59:08 +0000 |
parents | 9ddea0c614ee |
children | f2f73a2171e6 |
rev | line source |
---|---|
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
1 #!/usr/bin/python |
0 | 2 """ |
3 | |
4 this is the only process to talk to the dmx hardware. other clients | |
5 can connect to this server and present dmx output, and this server | |
6 will max ('pile-on') all the client requests. | |
7 | |
8 this server has a level display which is the final set of values that | |
9 goes to the hardware. | |
10 | |
11 clients shall connect to the xmlrpc server and send: | |
12 | |
13 their PID (or some other cookie) | |
14 | |
15 a length-n list of 0..1 levels which will represent the channel | |
16 values for the n first dmx channels. | |
17 | |
18 server is port 8030; xmlrpc method is called outputlevels(pid,levellist). | |
19 | |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
20 todo: |
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
21 save dmx on quit and restore on restart |
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
22 if parport fails, run in dummy mode (and make an option for that too) |
0 | 23 """ |
24 | |
25 from __future__ import division | |
26 from twisted.internet import reactor | |
27 from twisted.web import xmlrpc, server | |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
28 import sys,time |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
29 from optik import OptionParser |
0 | 30 from io import ParportDMX |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
31 from updatefreq import Updatefreq |
0 | 32 |
33 class XMLRPCServe(xmlrpc.XMLRPC): | |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
34 def __init__(self,options): |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
35 |
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
36 xmlrpc.XMLRPC.__init__(self) |
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
37 |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
38 self.clientlevels={} # clientID : list of levels |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
39 self.lastseen={} # clientID : time last seen |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
40 self.clientfreq={} # clientID : updatefreq |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
41 |
0 | 42 self.combinedlevels=[] # list of levels, after max'ing the clients |
43 self.clientschanged=1 # have clients sent anything since the last send? | |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
44 self.options=options |
0 | 45 |
46 print "starting parport connection" | |
47 self.parportdmx=ParportDMX() | |
112
afbdae5e1359
dmx light output is now via a separate process which light8 talks to.
drewp
parents:
0
diff
changeset
|
48 self.parportdmx.golive() |
0 | 49 |
50 # start the loop | |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
51 self.updatefreq=Updatefreq() |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
52 self.num_unshown_updates=None |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
53 self.lastshownlevels=None |
0 | 54 self.sendlevels() |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
55 |
0 | 56 |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
57 def purgeclients(self): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
58 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
59 """forget about any clients who haven't sent levels in a while |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
60 (5 seconds)""" |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
61 now=time.time() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
62 for cid,lastseen in self.lastseen.items(): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
63 if lastseen<now-5: |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
64 print "forgetting client %s (no activity for 5sec)" % cid |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
65 del self.clientlevels[cid] |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
66 del self.lastseen[cid] |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
67 del self.clientfreq[cid] |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
68 |
0 | 69 def sendlevels(self): |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
70 reactor.callLater(1/20,self.sendlevels) |
0 | 71 if self.clientschanged: |
72 # recalc levels | |
73 | |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
74 self.purgeclients() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
75 self.calclevels() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
76 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
77 if (self.num_unshown_updates is None or # first time |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
78 self.options.fast_updates or # show always |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
79 (self.combinedlevels!=self.lastshownlevels and # changed |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
80 self.num_unshown_updates>10)): # not too frequent |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
81 self.num_unshown_updates=0 |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
82 self.printlevels() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
83 self.lastshownlevels=self.combinedlevels[:] |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
84 else: |
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
85 self.num_unshown_updates+=1 |
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
86 |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
87 if (self.num_unshown_updates-1)%50==0: |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
88 self.printstats() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
89 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
90 self.sendlevels_dmx() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
91 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
92 def calclevels(self): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
93 """combine all the known client levels into self.combinedlevels""" |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
94 self.combinedlevels=[] |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
95 for chan in range(0,self.parportdmx.dimmers): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
96 x=0 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
97 for clientlist in self.clientlevels.values(): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
98 if len(clientlist)>chan: |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
99 # clamp client levels to 0..1 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
100 cl=max(0,min(1,clientlist[chan])) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
101 x=max(x,cl) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
102 self.combinedlevels.append(x) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
103 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
104 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
105 def printlevels(self): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
106 """write all the levels to stdout""" |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
107 print "Levels:","".join(["% 2d "%(x*100) for |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
108 x in self.combinedlevels]) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
109 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
110 def printstats(self): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
111 """print the clock, freq, etc, with a \r at the end""" |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
112 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
113 sys.stdout.write("dmxserver up at %s, [server %s] "% |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
114 (time.strftime("%H:%M:%S"), |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
115 str(self.updatefreq), |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
116 )) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
117 for cid,freq in self.clientfreq.items(): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
118 sys.stdout.write("[%s %s] " % (cid,str(freq))) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
119 sys.stdout.write("\r") |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
120 sys.stdout.flush() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
121 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
122 |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
123 def sendlevels_dmx(self): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
124 """output self.combinedlevels to dmx, and keep the updates/sec stats""" |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
125 # they'll get divided by 100 |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
126 if self.parportdmx: |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
127 self.parportdmx.sendlevels([l*100 for l in self.combinedlevels]) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
128 self.updatefreq.update() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
129 |
0 | 130 def xmlrpc_echo(self,x): |
131 return x | |
132 | |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
133 def xmlrpc_outputlevels(self,cid,levellist): |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
134 """send a unique id for your client (name+pid maybe), then |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
135 the variable-length dmx levellist (scaled 0..1)""" |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
136 self.clientlevels[cid]=levellist |
112
afbdae5e1359
dmx light output is now via a separate process which light8 talks to.
drewp
parents:
0
diff
changeset
|
137 self.clientschanged=1 |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
138 if cid not in self.lastseen: |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
139 print "hello new client %s" % cid |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
140 self.clientfreq[cid]=Updatefreq() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
141 self.lastseen[cid]=time.time() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
142 self.clientfreq[cid].update() |
0 | 143 return "ok" |
144 | |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
145 parser=OptionParser() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
146 parser.add_option("-f","--fast-updates",action='store_true', |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
147 help=('display all dmx output to stdout instead ' |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
148 'of the usual reduced output')) |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
149 (options,songfiles)=parser.parse_args() |
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
150 |
116
9ddea0c614ee
much prettier stdout, including a clock (so you can tell the server's running)
drewp
parents:
112
diff
changeset
|
151 print "starting xmlrpc server on port 8030" |
118
2c25a69c084d
now tracks update frequencies of the server and each client
drewp
parents:
116
diff
changeset
|
152 reactor.listenTCP(8030,server.Site(XMLRPCServe(options))) |
0 | 153 reactor.run() |
154 |