annotate light8/dmxserver.py @ 0:45b12307c695

Initial revision
author drewp
date Wed, 03 Jul 2002 09:37:57 +0000
parents
children afbdae5e1359
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
1 #!/usr/bin/python
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
20 todo:
45b12307c695 Initial revision
drewp
parents:
diff changeset
21 save dmx on quit and restore on restart
45b12307c695 Initial revision
drewp
parents:
diff changeset
22 if parport fails, run in dummy mode (and make an option for that too)
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
45b12307c695 Initial revision
drewp
parents:
diff changeset
28 import sys,time,os
45b12307c695 Initial revision
drewp
parents:
diff changeset
29 from optparse import OptionParser
45b12307c695 Initial revision
drewp
parents:
diff changeset
30 from io import ParportDMX
45b12307c695 Initial revision
drewp
parents:
diff changeset
31 from updatefreq import Updatefreq
45b12307c695 Initial revision
drewp
parents:
diff changeset
32
45b12307c695 Initial revision
drewp
parents:
diff changeset
33 class XMLRPCServe(xmlrpc.XMLRPC):
45b12307c695 Initial revision
drewp
parents:
diff changeset
34 def __init__(self,options):
45b12307c695 Initial revision
drewp
parents:
diff changeset
35
45b12307c695 Initial revision
drewp
parents:
diff changeset
36 xmlrpc.XMLRPC.__init__(self)
45b12307c695 Initial revision
drewp
parents:
diff changeset
37
45b12307c695 Initial revision
drewp
parents:
diff changeset
38 self.clientlevels={} # clientID : list of levels
45b12307c695 Initial revision
drewp
parents:
diff changeset
39 self.lastseen={} # clientID : time last seen
45b12307c695 Initial revision
drewp
parents:
diff changeset
40 self.clientfreq={} # clientID : updatefreq
45b12307c695 Initial revision
drewp
parents:
diff changeset
41
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?
45b12307c695 Initial revision
drewp
parents:
diff changeset
44 self.options=options
45b12307c695 Initial revision
drewp
parents:
diff changeset
45 self.lastupdate=0 # time of last dmx send
45b12307c695 Initial revision
drewp
parents:
diff changeset
46 self.laststatsprint=0 # time
45b12307c695 Initial revision
drewp
parents:
diff changeset
47
45b12307c695 Initial revision
drewp
parents:
diff changeset
48 # desired seconds between sendlevels() calls
45b12307c695 Initial revision
drewp
parents:
diff changeset
49 self.calldelay=1/options.updates_per_sec
45b12307c695 Initial revision
drewp
parents:
diff changeset
50
45b12307c695 Initial revision
drewp
parents:
diff changeset
51 print "starting parport connection"
45b12307c695 Initial revision
drewp
parents:
diff changeset
52 self.parportdmx=ParportDMX()
45b12307c695 Initial revision
drewp
parents:
diff changeset
53 if os.environ.get('DMXDUMMY',0):
45b12307c695 Initial revision
drewp
parents:
diff changeset
54 self.parportdmx.godummy()
45b12307c695 Initial revision
drewp
parents:
diff changeset
55 else:
45b12307c695 Initial revision
drewp
parents:
diff changeset
56 self.parportdmx.golive()
45b12307c695 Initial revision
drewp
parents:
diff changeset
57
45b12307c695 Initial revision
drewp
parents:
diff changeset
58
45b12307c695 Initial revision
drewp
parents:
diff changeset
59 self.updatefreq=Updatefreq() # freq of actual dmx sends
45b12307c695 Initial revision
drewp
parents:
diff changeset
60 self.num_unshown_updates=None
45b12307c695 Initial revision
drewp
parents:
diff changeset
61 self.lastshownlevels=None
45b12307c695 Initial revision
drewp
parents:
diff changeset
62 # start the loop
45b12307c695 Initial revision
drewp
parents:
diff changeset
63 self.sendlevels()
45b12307c695 Initial revision
drewp
parents:
diff changeset
64
45b12307c695 Initial revision
drewp
parents:
diff changeset
65 # the other loop
45b12307c695 Initial revision
drewp
parents:
diff changeset
66 self.purgeclients()
45b12307c695 Initial revision
drewp
parents:
diff changeset
67
45b12307c695 Initial revision
drewp
parents:
diff changeset
68 def purgeclients(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
69
45b12307c695 Initial revision
drewp
parents:
diff changeset
70 """forget about any clients who haven't sent levels in a while.
45b12307c695 Initial revision
drewp
parents:
diff changeset
71 this runs in a loop"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
72
45b12307c695 Initial revision
drewp
parents:
diff changeset
73 purge_age=10 # seconds
45b12307c695 Initial revision
drewp
parents:
diff changeset
74
45b12307c695 Initial revision
drewp
parents:
diff changeset
75 reactor.callLater(1,self.purgeclients)
45b12307c695 Initial revision
drewp
parents:
diff changeset
76
45b12307c695 Initial revision
drewp
parents:
diff changeset
77 now=time.time()
45b12307c695 Initial revision
drewp
parents:
diff changeset
78 cids=self.clientlevels.keys()
45b12307c695 Initial revision
drewp
parents:
diff changeset
79 for cid in cids:
45b12307c695 Initial revision
drewp
parents:
diff changeset
80 lastseen=self.lastseen[cid]
45b12307c695 Initial revision
drewp
parents:
diff changeset
81 if lastseen<now-purge_age:
45b12307c695 Initial revision
drewp
parents:
diff changeset
82 print ("forgetting client %s (no activity for %s sec)" %
45b12307c695 Initial revision
drewp
parents:
diff changeset
83 (cid,purge_age))
45b12307c695 Initial revision
drewp
parents:
diff changeset
84 del self.clientlevels[cid]
45b12307c695 Initial revision
drewp
parents:
diff changeset
85 del self.clientfreq[cid]
45b12307c695 Initial revision
drewp
parents:
diff changeset
86 del self.lastseen[cid]
45b12307c695 Initial revision
drewp
parents:
diff changeset
87
45b12307c695 Initial revision
drewp
parents:
diff changeset
88 def sendlevels(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
89
45b12307c695 Initial revision
drewp
parents:
diff changeset
90 """sends to dmx if levels have changed, or if we havent sent
45b12307c695 Initial revision
drewp
parents:
diff changeset
91 in a while"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
92
45b12307c695 Initial revision
drewp
parents:
diff changeset
93 reactor.callLater(self.calldelay,self.sendlevels)
45b12307c695 Initial revision
drewp
parents:
diff changeset
94
45b12307c695 Initial revision
drewp
parents:
diff changeset
95 if self.clientschanged:
45b12307c695 Initial revision
drewp
parents:
diff changeset
96 # recalc levels
45b12307c695 Initial revision
drewp
parents:
diff changeset
97
45b12307c695 Initial revision
drewp
parents:
diff changeset
98 self.calclevels()
45b12307c695 Initial revision
drewp
parents:
diff changeset
99
45b12307c695 Initial revision
drewp
parents:
diff changeset
100 if (self.num_unshown_updates is None or # first time
45b12307c695 Initial revision
drewp
parents:
diff changeset
101 self.options.fast_updates or # show always
45b12307c695 Initial revision
drewp
parents:
diff changeset
102 (self.combinedlevels!=self.lastshownlevels and # changed
45b12307c695 Initial revision
drewp
parents:
diff changeset
103 self.num_unshown_updates>5)): # not too frequent
45b12307c695 Initial revision
drewp
parents:
diff changeset
104 self.num_unshown_updates=0
45b12307c695 Initial revision
drewp
parents:
diff changeset
105 self.printlevels()
45b12307c695 Initial revision
drewp
parents:
diff changeset
106 self.lastshownlevels=self.combinedlevels[:]
45b12307c695 Initial revision
drewp
parents:
diff changeset
107 else:
45b12307c695 Initial revision
drewp
parents:
diff changeset
108 self.num_unshown_updates+=1
45b12307c695 Initial revision
drewp
parents:
diff changeset
109
45b12307c695 Initial revision
drewp
parents:
diff changeset
110 if time.time()>self.laststatsprint+2:
45b12307c695 Initial revision
drewp
parents:
diff changeset
111 self.laststatsprint=time.time()
45b12307c695 Initial revision
drewp
parents:
diff changeset
112 self.printstats()
45b12307c695 Initial revision
drewp
parents:
diff changeset
113
45b12307c695 Initial revision
drewp
parents:
diff changeset
114 if self.clientschanged or time.time()>self.lastupdate+1:
45b12307c695 Initial revision
drewp
parents:
diff changeset
115 self.lastupdate=time.time()
45b12307c695 Initial revision
drewp
parents:
diff changeset
116 self.sendlevels_dmx()
45b12307c695 Initial revision
drewp
parents:
diff changeset
117
45b12307c695 Initial revision
drewp
parents:
diff changeset
118 self.clientschanged=0 # clear the flag
45b12307c695 Initial revision
drewp
parents:
diff changeset
119
45b12307c695 Initial revision
drewp
parents:
diff changeset
120 def calclevels(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
121 """combine all the known client levels into self.combinedlevels"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
122 self.combinedlevels=[]
45b12307c695 Initial revision
drewp
parents:
diff changeset
123 for chan in range(0,self.parportdmx.dimmers):
45b12307c695 Initial revision
drewp
parents:
diff changeset
124 x=0
45b12307c695 Initial revision
drewp
parents:
diff changeset
125 for clientlist in self.clientlevels.values():
45b12307c695 Initial revision
drewp
parents:
diff changeset
126 if len(clientlist)>chan:
45b12307c695 Initial revision
drewp
parents:
diff changeset
127 # clamp client levels to 0..1
45b12307c695 Initial revision
drewp
parents:
diff changeset
128 cl=max(0,min(1,clientlist[chan]))
45b12307c695 Initial revision
drewp
parents:
diff changeset
129 x=max(x,cl)
45b12307c695 Initial revision
drewp
parents:
diff changeset
130 self.combinedlevels.append(x)
45b12307c695 Initial revision
drewp
parents:
diff changeset
131
45b12307c695 Initial revision
drewp
parents:
diff changeset
132 def printlevels(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
133 """write all the levels to stdout"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
134 print "Levels:","".join(["% 2d "%(x*100) for
45b12307c695 Initial revision
drewp
parents:
diff changeset
135 x in self.combinedlevels])
45b12307c695 Initial revision
drewp
parents:
diff changeset
136
45b12307c695 Initial revision
drewp
parents:
diff changeset
137 def printstats(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
138 """print the clock, freq, etc, with a \r at the end"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
139
45b12307c695 Initial revision
drewp
parents:
diff changeset
140 sys.stdout.write("dmxserver up at %s, [polls %s] "%
45b12307c695 Initial revision
drewp
parents:
diff changeset
141 (time.strftime("%H:%M:%S"),
45b12307c695 Initial revision
drewp
parents:
diff changeset
142 str(self.updatefreq),
45b12307c695 Initial revision
drewp
parents:
diff changeset
143 ))
45b12307c695 Initial revision
drewp
parents:
diff changeset
144 for cid,freq in self.clientfreq.items():
45b12307c695 Initial revision
drewp
parents:
diff changeset
145 sys.stdout.write("[%s %s] " % (cid,str(freq)))
45b12307c695 Initial revision
drewp
parents:
diff changeset
146 sys.stdout.write("\r")
45b12307c695 Initial revision
drewp
parents:
diff changeset
147 sys.stdout.flush()
45b12307c695 Initial revision
drewp
parents:
diff changeset
148
45b12307c695 Initial revision
drewp
parents:
diff changeset
149 def sendlevels_dmx(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
150 """output self.combinedlevels to dmx, and keep the updates/sec stats"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
151 # they'll get divided by 100
45b12307c695 Initial revision
drewp
parents:
diff changeset
152 if self.parportdmx:
45b12307c695 Initial revision
drewp
parents:
diff changeset
153 self.parportdmx.sendlevels([l*100 for l in self.combinedlevels])
45b12307c695 Initial revision
drewp
parents:
diff changeset
154 self.updatefreq.update()
45b12307c695 Initial revision
drewp
parents:
diff changeset
155
45b12307c695 Initial revision
drewp
parents:
diff changeset
156 def xmlrpc_echo(self,x):
45b12307c695 Initial revision
drewp
parents:
diff changeset
157 return x
45b12307c695 Initial revision
drewp
parents:
diff changeset
158
45b12307c695 Initial revision
drewp
parents:
diff changeset
159 def xmlrpc_outputlevels(self,cid,levellist):
45b12307c695 Initial revision
drewp
parents:
diff changeset
160 """send a unique id for your client (name+pid maybe), then
45b12307c695 Initial revision
drewp
parents:
diff changeset
161 the variable-length dmx levellist (scaled 0..1)"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
162 if levellist!=self.clientlevels.get(cid,None):
45b12307c695 Initial revision
drewp
parents:
diff changeset
163 self.clientlevels[cid]=levellist
45b12307c695 Initial revision
drewp
parents:
diff changeset
164 self.clientschanged=1
45b12307c695 Initial revision
drewp
parents:
diff changeset
165 if cid not in self.lastseen:
45b12307c695 Initial revision
drewp
parents:
diff changeset
166 print "hello new client %s" % cid
45b12307c695 Initial revision
drewp
parents:
diff changeset
167 self.clientfreq[cid]=Updatefreq()
45b12307c695 Initial revision
drewp
parents:
diff changeset
168
45b12307c695 Initial revision
drewp
parents:
diff changeset
169 self.lastseen[cid]=time.time()
45b12307c695 Initial revision
drewp
parents:
diff changeset
170 self.clientfreq[cid].update()
45b12307c695 Initial revision
drewp
parents:
diff changeset
171 return "ok"
45b12307c695 Initial revision
drewp
parents:
diff changeset
172
45b12307c695 Initial revision
drewp
parents:
diff changeset
173 parser=OptionParser()
45b12307c695 Initial revision
drewp
parents:
diff changeset
174 parser.add_option("-f","--fast-updates",action='store_true',
45b12307c695 Initial revision
drewp
parents:
diff changeset
175 help=('display all dmx output to stdout instead '
45b12307c695 Initial revision
drewp
parents:
diff changeset
176 'of the usual reduced output'))
45b12307c695 Initial revision
drewp
parents:
diff changeset
177 parser.add_option("-r","--updates-per-sec",type='float',default=20,
45b12307c695 Initial revision
drewp
parents:
diff changeset
178 help=('dmx output frequency'))
45b12307c695 Initial revision
drewp
parents:
diff changeset
179 (options,songfiles)=parser.parse_args()
45b12307c695 Initial revision
drewp
parents:
diff changeset
180
45b12307c695 Initial revision
drewp
parents:
diff changeset
181 print options
45b12307c695 Initial revision
drewp
parents:
diff changeset
182
45b12307c695 Initial revision
drewp
parents:
diff changeset
183 print "starting xmlrpc server on port 8030"
45b12307c695 Initial revision
drewp
parents:
diff changeset
184 reactor.listenTCP(8030,server.Site(XMLRPCServe(options)))
45b12307c695 Initial revision
drewp
parents:
diff changeset
185 reactor.run()
45b12307c695 Initial revision
drewp
parents:
diff changeset
186