Changeset - d5e99fee786d
[Not reviewed]
default
0 7 0
Drew Perttula - 10 years ago 2015-06-08 06:53:12
drewp@bigasterisk.com
twisted uses zmq (not xmlrpc) to send levels to dmxserver
Ignore-this: 78d627e1ff8c8e83b50ae099d373b8c1
7 files changed with 36 insertions and 12 deletions:
0 comments (0 inline, 0 general)
bin/dmxserver
Show inline comments
 
@@ -25,24 +25,35 @@ todo:
 
from __future__ import division
 
from twisted.internet import reactor
 
from twisted.web import xmlrpc, server
 
import sys,time,os
 
from optparse import OptionParser
 
import run_local
 
import txosc.dispatch, txosc.async
 
from light9.io import ParportDMX, UsbDMX
 

	
 
from light9.updatefreq import Updatefreq
 
from light9 import networking
 

	
 
from txzmq import ZmqEndpoint, ZmqFactory, ZmqPullConnection, ZmqRequestTimeoutError
 
import json
 

	
 
def startZmq(port, outputlevels):
 
    zf = ZmqFactory()
 
    e = ZmqEndpoint('bind', 'tcp://*:%s' % port)
 
    s = ZmqPullConnection(zf, e)
 
    def onPull(message):
 
        msg = json.loads(message[0])
 
        outputlevels(msg['clientid'], msg['levellist'])
 
    s.onPull = onPull
 

	
 
class ReceiverApplication(object):
 
    """
 
    receive UDP OSC messages. address is /dmx/1 for dmx channel 1,
 
    arguments are 0-1 floats for that channel and any number of
 
    following channels.
 
    """
 
    def __init__(self, port, lightServer):
 
        self.port = port
 
        self.lightServer = lightServer
 
        self.receiver = txosc.dispatch.Receiver()
 
        self.receiver.addCallback("/dmx/*", self.pixel_handler)
 
@@ -239,16 +250,18 @@ parser.add_option("-n", "--dummy", actio
 

	
 
print options
 

	
 
if options.dummy:
 
    os.environ['DMXDUMMY'] = "1"
 

	
 

	
 
port = networking.dmxServer.port
 
print "starting xmlrpc server on port %s" % port
 
xmlrpcServe = XMLRPCServe(options)
 
reactor.listenTCP(port,server.Site(xmlrpcServe))
 

	
 
startZmq(networking.dmxServerZmq.port, xmlrpcServe.xmlrpc_outputlevels)
 
                  
 
oscApp = ReceiverApplication(9051, xmlrpcServe)
 

	
 
reactor.run()
 

	
light9/dmxclient.py
Show inline comments
 
""" module for clients to use for easy talking to the dmx
 
server. sending levels is now a simple call to
 
dmxclient.outputlevels(..)
 

	
 
client id is formed from sys.argv[0] and the PID.  """
 

	
 
import xmlrpclib, os, sys, socket, time, logging
 
from twisted.internet import defer
 
from txzmq import ZmqEndpoint, ZmqFactory, ZmqPushConnection
 
import json
 

	
 
from light9 import networking
 
_dmx=None
 
log = logging.getLogger('dmxclient')
 

	
 
procname = os.path.basename(sys.argv[0])
 
procname = procname.replace('.py', '')
 
_id = "%s-%s-%s" % (procname, socket.gethostname(), os.getpid())
 

	
 
class TwistedZmqClient(object):
 
    def __init__(self, service):
 
        zf = ZmqFactory()
 
        e = ZmqEndpoint('connect', 'tcp://%s:%s' % (service.host, service.port))
 
        self.conn = ZmqPushConnection(zf, e)
 
        
 
    def send(self, clientid, levellist):
 
        self.conn.push(json.dumps({'clientid': clientid, 'levellist': levellist}))
 

	
 
def outputlevels(levellist,twisted=0,clientid=_id):
 
    """present a list of dmx channel levels, each scaled from
 
    0..1. list can be any length- it will apply to the first len() dmx
 
    channels.
 

	
 
    if the server is not found, outputlevels will block for a
 
    second."""
 

	
 
    global _dmx, _id
 

	
 
    if _dmx is None:
 
        url = networking.dmxServer.url
 
        if not twisted:
 
            _dmx = xmlrpclib.Server(url)
 
        else:
 
            from twisted.web.xmlrpc import Proxy
 
            _dmx = Proxy(url)
 
            _dmx = TwistedZmqClient(networking.dmxServerZmq)
 

	
 
    if not twisted:
 
        try:
 
            _dmx.outputlevels(clientid, levellist)
 
        except socket.error, e:
 
            log.error("dmx server error %s, waiting" % e)
 
            time.sleep(1)
 
        except xmlrpclib.Fault,e:
 
            log.error("outputlevels had xml fault: %s" % e)
 
            time.sleep(1)
 
    else:
 
        def err(error):
 
            log.error("dmx server error talking to %s: %s",
 
                      networking.dmxServer.url, error.getErrorMessage())
 
            time.sleep(1)
 
        d = _dmx.callRemote('outputlevels', clientid, levellist)
 
        d.addErrback(err)
 
        return d
 

	
 
        _dmx.send(clientid, levellist)
 
        return defer.succeed(None)
 
    
 
dummy = os.getenv('DMXDUMMY')
 
if dummy:
 
    print "dmxclient: DMX is in dummy mode."
 
    def outputlevels(*args, **kw):
 
        pass
light9/effecteval/effectloop.py
Show inline comments
 
@@ -89,25 +89,25 @@ class EffectLoop(object):
 
            # this may be piling on the handlers
 
            self.graph.addHandler(self.setEffects)
 

	
 
        elapsed = time.time() - t1
 
        reactor.callLater(max(0, self.period - elapsed), self.updateTimeFromMusic)
 

	
 
    def estimatedSongTime(self):
 
        now = time.time()
 
        t = self.songTime
 
        if self.currentPlaying:
 
            t += max(0, now - self.songTimeFetch)
 
        return t
 
        
 

	
 
    @inlineCallbacks
 
    def sendLevels(self):
 
        t1 = time.time()
 
        log.debug("time since last call: %.1f ms" % (1000 * (t1 - self.lastSendLevelsTime)))
 
        self.lastSendLevelsTime = t1
 
        try:
 
            with self.stats.sendLevels.time():
 
                if self.currentSong is not None:
 
                    with self.stats.evals.time():
 
                        outputs = self.allEffectOutputs(self.estimatedSongTime())
 
                    combined = self.combineOutputs(outputs)
 
                    self.logLevels(t1, combined)
light9/networking.py
Show inline comments
 
@@ -28,23 +28,24 @@ class ServiceAddress(object):
 
        return host
 

	
 
    @property
 
    def url(self):
 
        return self._url()
 
    value = url
 
    
 
    def path(self, more):
 
        return self.url + str(more)
 

	
 
curveCalc = ServiceAddress(L9['curveCalc'])
 
dmxServer = ServiceAddress(L9['dmxServer'])
 
dmxServerZmq = ServiceAddress(L9['dmxServerZmq'])
 
effectEval = ServiceAddress(L9['effectEval'])
 
keyboardComposer = ServiceAddress(L9['keyboardComposer'])
 
musicPlayer = ServiceAddress(L9['musicPlayer'])
 
oscDmxServer = ServiceAddress(L9['oscDmxServer'])
 
picamserve = ServiceAddress(L9['picamserve'])
 
rdfdb = ServiceAddress(L9['rdfdb'])
 
subComposer = ServiceAddress(L9['subComposer'])
 
subServer = ServiceAddress(L9['subServer'])
 
vidref = ServiceAddress(L9['vidref'])
 

	
 
patchReceiverUpdateHost = ServiceAddress(L9['patchReceiverUpdateHost'])
makefile
Show inline comments
 
@@ -42,25 +42,25 @@ tkdnd_build:
 
	# get tkdnd r95 with subversion
 
	# then apply tkdnd-patch-on-r95 to that
 
	cd tkdnd/trunk
 
	./configure
 
	make
 

	
 
bin/ascoltami2: gst_packages link_to_sys_packages
 

	
 
gst_packages:
 
	sudo aptitude install python-gi gir1.2-gst-plugins-base-1.0 libgirepository-1.0-1 gir1.2-gstreamer-1.0 gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-pulseaudio 
 

	
 
packages:
 
	sudo aptitude install coffeescript freemind normalize-audio audacity python-pygoocanvas python-pygame gir1.2-goocanvas-2.0-9 libffi-dev tix
 
	sudo aptitude install coffeescript freemind normalize-audio audacity python-pygoocanvas python-pygame gir1.2-goocanvas-2.0-9 libffi-dev tix libzmq3
 

	
 
raspberry_pi_virtualenv:
 
	mkdir -p env_pi
 
	virtualenv --system-site-packages env_pi
 

	
 
raspberry_pi_packages:
 
	sudo apt-get install python-picamera python-twisted 
 
	env_pi/bin/pip install cyclone coloredlogs
 

	
 
darcs_show_checkpoint:
 
	darcs add --quiet --recursive ${LIGHT9_SHOW} 
 
	darcs rec -a -m "checkpoint show data" ${LIGHT9_SHOW}
pydeps
Show inline comments
 
@@ -17,12 +17,14 @@ pyjade==3.0.0
 
python-dateutil==2.4.2
 
txosc==0.2.0
 
service_identity==0.2
 
Pillow==2.8.1
 
faulthandler==2.3
 
treq==0.2.1
 
mock==1.0.1
 
toposort==1.0
 
pyserial==2.7
 

	
 
scales==1.0.9
 
statprof==0.1.2
 
txzmq==0.7.4
 

	
show/dance2014/networking.n3
Show inline comments
 
@prefix : <http://light9.bigasterisk.com/> .
 
@prefix show: <http://light9.bigasterisk.com/show/> .
 
@prefix sh: <http://light9.bigasterisk.com/show/dance2014/> .
 

	
 
show:dance2014 :networking sh:netHome .
 
sh:netHome
 
  :patchReceiverUpdateHost "localhost";
 
  :curveCalc        <http://dash:8060/>;
 
  :dmxServer        <http://dash:8030/>;
 
  :dmxServerZmq     <http://dash:8031/>;
 
  :effectEval       <http://dash:8070/>;
 
  :keyboardComposer <http://dash:8050/>;
 
  :musicPlayer      <http://dash:8040/>;
 
  :oscDmxServer     <udp://dash:9050/>;
 
  :picamserve       <http://10.2.0.3:8001/>;
 
  :rdfdb            <http://localhost:8051/>;
 
  :subComposer      <http://dash:8055/>;
 
  :subServer        <http://dash:8052/>;
 
  :vidref           <http://dash:8053/> .
 

	
 
:curveCalc        :urlPath "curveCalc" .
 
:dmxServer        :urlPath "dmxServer" .
0 comments (0 inline, 0 general)