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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
2 """
45b12307c695 Initial revision
drewp
parents:
diff changeset
3
45b12307c695 Initial revision
drewp
parents:
diff changeset
4 this is the only process to talk to the dmx hardware. other clients
45b12307c695 Initial revision
drewp
parents:
diff changeset
5 can connect to this server and present dmx output, and this server
45b12307c695 Initial revision
drewp
parents:
diff changeset
6 will max ('pile-on') all the client requests.
45b12307c695 Initial revision
drewp
parents:
diff changeset
7
45b12307c695 Initial revision
drewp
parents:
diff changeset
8 this server has a level display which is the final set of values that
45b12307c695 Initial revision
drewp
parents:
diff changeset
9 goes to the hardware.
45b12307c695 Initial revision
drewp
parents:
diff changeset
10
45b12307c695 Initial revision
drewp
parents:
diff changeset
11 clients shall connect to the xmlrpc server and send:
45b12307c695 Initial revision
drewp
parents:
diff changeset
12
45b12307c695 Initial revision
drewp
parents:
diff changeset
13 their PID (or some other cookie)
45b12307c695 Initial revision
drewp
parents:
diff changeset
14
45b12307c695 Initial revision
drewp
parents:
diff changeset
15 a length-n list of 0..1 levels which will represent the channel
45b12307c695 Initial revision
drewp
parents:
diff changeset
16 values for the n first dmx channels.
45b12307c695 Initial revision
drewp
parents:
diff changeset
17
45b12307c695 Initial revision
drewp
parents:
diff changeset
18 server is port 8030; xmlrpc method is called outputlevels(pid,levellist).
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
23 """
45b12307c695 Initial revision
drewp
parents:
diff changeset
24
45b12307c695 Initial revision
drewp
parents:
diff changeset
25 from __future__ import division
45b12307c695 Initial revision
drewp
parents:
diff changeset
26 from twisted.internet import reactor
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
32
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
42 self.combinedlevels=[] # list of levels, after max'ing the clients
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
45
45b12307c695 Initial revision
drewp
parents:
diff changeset
46 print "starting parport connection"
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
49
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
54 self.sendlevels()
118
2c25a69c084d now tracks update frequencies of the server and each client
drewp
parents: 116
diff changeset
55
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
71 if self.clientschanged:
45b12307c695 Initial revision
drewp
parents:
diff changeset
72 # recalc levels
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
130 def xmlrpc_echo(self,x):
45b12307c695 Initial revision
drewp
parents:
diff changeset
131 return x
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
143 return "ok"
45b12307c695 Initial revision
drewp
parents:
diff changeset
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
153 reactor.run()
45b12307c695 Initial revision
drewp
parents:
diff changeset
154