示例#1
0
class DMXServerThread(threading.Thread):
    wrapper = None
    TICK_INTERVAL = 1  # in ms
    SPEED = 3  # speed multiplier
    targetValues = [0, 0, 0, 0, 0, 0, 0, 0, 0]
    currentValues = [0, 0, 0, 0, 0, 0, 0, 0, 0]

    def __init__(self):
        print "DMXServerThread Init"
        threading.Thread.__init__(self)
        self.wrapper = ClientWrapper()

    def DmxSent(self, state):
        if not state.Succeeded():
            print "DMX Sending Failed for some reason"
            self.wrapper.Stop()

    def SendDMXFrame(self):
        # continuously schedule the next function call
        self.wrapper.AddEvent(self.TICK_INTERVAL, self.SendDMXFrame)

        # if current values are within range of target, set to target; prevent target oscillation
        for i, v in enumerate(self.currentValues):
            diff = abs(self.targetValues[i] - v)
            if diff > 0 and diff <= self.SPEED:
                #print "Forcing channel %s to %s" % (i, v)
                self.currentValues[i] = v

        # Don't flood the dmx controller with unnecessary messages
        if self.currentValues == self.targetValues:
            return

        # compute next current value for each channel & add to frame
        data = array.array('B')
        for i, v in enumerate(self.targetValues):
            newVal = self.currentValues[i] + (cmp(
                self.targetValues[i] - self.currentValues[i], 0) * self.SPEED)
            #print newVal
            if (newVal > 255): newVal = 255
            if (newVal < 0): newVal = 0
            self.currentValues[i] = newVal

            data.append(self.currentValues[i])

        self.wrapper.Client().SendDmx(1, data, self.DmxSent)

    def setTargets(self, _targetValues={}):
        for k, v in _targetValues.iteritems():
            if not isinstance(k, int) or k > 10:
                print "Target channel is not an int or is out of range"
                return
            self.targetValues[k] = v

    def stop(self):
        self.wrapper.Stop()

    def run(self):
        self.wrapper.AddEvent(self.TICK_INTERVAL, self.SendDMXFrame)
        self.wrapper.Run()
示例#2
0
class Main:
    def __init__(self):
        self.settings = yaml.load(open('settings.yaml', 'r'))
        self.serv = sockethandler.server(
            self.settings.get('address') or 'localhost',
            self.settings.get('port') or 25500)
        self.clients = []

        self.switches = []
        for switch in self.settings['switches'].items():
            self.switches.append(Switch(switch[0], switch[1]))

        self.current_dmx = array.array('B', [0] * 512)

        self.wrapper = ClientWrapper()
        self.wrapper.AddEvent(100, self.loop)

    def loop(self):
        self.wrapper.AddEvent(100, self.loop)
        for msg, addr in self.serv.recv():
            print(msg, addr)
            if not addr in self.clients:
                self.clients.append(addr)
                print('client ' + str(addr) + ' connected')
            if msg[0] == 'hi':
                self.serv.send(['hi'] + [s.name for s in self.switches], addr)
            elif msg[0] == 'on':
                self.switches[msg[1]].on()
            elif msg[0] == 'off':
                self.switches[msg[1]].off()
            elif msg[0] == 'bye':
                print('client ' + str(addr) + ' disconnected')
                self.clients.remove(addr)

        dmx = array.array('B', [0] * 512)
        msg = ['sw']

        for switch in self.switches:
            addrs, val = switch.tick()
            for addr in addrs:
                dmx[addr - 1] = val
            msg.append(switch.active)

        for client in self.clients:
            self.serv.send(msg, client)

        if not dmx == self.current_dmx:
            self.wrapper.Client().SendDmx(self.settings['universe'], dmx,
                                          self.DmxSent)
            self.current_dmx = dmx

    def DmxSent(self, state):
        if not state.Succeeded():
            wrapper.Stop()
示例#3
0
def start_wrapper():
  global wrapper
  global client
  wrapper = ClientWrapper()
  client = wrapper.Client()
  wrapper.AddEvent(0, main_loop)
  wrapper.Run()
示例#4
0
class DmxControlThread(threading.Thread):
    def __init__(self, name, ola_universe, dmx_state, interface_fs=30):
        threading.Thread.__init__(self)
        self.daemon = True
        self.name = name
        self.ola_universe = ola_universe
        self.dmx_state = dmx_state
        self.tick_interval = 1000./interface_fs

    def DmxSent(self, state):
        if not state.Succeeded():
            print 'DMX ERROR, NOT SUCCEEDED.'
            self.wrapper.Stop()

    def send_DMX(self):
        self.wrapper.AddEvent(self.tick_interval, self.send_DMX)

        new_state, modified = self.dmx_state.get()
        if modified:
            self.wrapper.Client().SendDmx(self.ola_universe,
                                            new_state,
                                            self.DmxSent)

    def close(self):
        print 'thread close'
        self.wrapper.Stop()

    def run(self):
        print 'starting DMX control thread'
        atexit.register(self.close)
        self.wrapper = ClientWrapper()
        self.wrapper.AddEvent(self.tick_interval, self.send_DMX)
        self.wrapper.Run()
示例#5
0
def run_strip_animation():
    wrapper = ClientWrapper()
    controller = SimpleFadeController(UPDATE_INTERVAL, wrapper)
    wrapper.AddEvent(SHUTDOWN_INTERVAL, wrapper.Stop)
    wrapper.Run()

    # Clears the variables, to prevent scope pollution.
    wrapper = None
    controller = None
示例#6
0
def squid(dmxrngs, delta_t):
    global rngs
    rngs = dmxrngs

    global tick_interval
    tick_interval = delta_t

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#7
0
def squid(dmxrngs):
    global rngs
    rngs = dmxrngs

    global tepilepsy
    tepilepsy = Tepilepsy()

    global pen
    pen = Pen(tepilepsy, '/home/squidlights/resources/tepilepsy_font.gif')

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#8
0
def something():
  ##SomethingHere?
try:
  wrapper = ClientWrapper()
  
  client = wrapper.Client()
  client.RegisterUniverse(universe, client.REGISTER, NewData)
  wrapper.Run()
  wrapper.AddEvent(10,something)
  

  
except KeyboardInterrupt:
    #clear()
    print("The End")
示例#9
0
def squid(dmxrngs, begclr, endclr, period):
    global frames
    frames = []

    #
    # precompute dmx packets for every frame
    #
    beg_hsv = colorsys.rgb_to_hsv(
        *tuple(map(operator.div, map(float, begclr), [255.0] * 3)))
    end_hsv = colorsys.rgb_to_hsv(
        *tuple(map(operator.div, map(float, endclr), [255.0] * 3)))
    for i in (range(0, period, TICK_INTERVAL) + [period]):
        progress = float(i) / float(period)

        hsv_delta = tuple(map(operator.sub, end_hsv, beg_hsv))
        hsv_addend = tuple(map(operator.mul, tuple([progress] * 3), hsv_delta))

        hsv = tuple(map(operator.add, beg_hsv, hsv_addend))
        clr = tuple(
            map(
                int,
                map(operator.mul, colorsys.hsv_to_rgb(*hsv),
                    tuple([255.0] * 3))))

        frame = []
        for j in range(0, len(dmxrngs)):
            dmxpacket = array.array('B', [0] * dmxrngs[j][1])
            for chann in range(dmxrngs[j][1], dmxrngs[j][2] - 2, 3):
                dmxpacket.append(clr[0])
                dmxpacket.append(clr[1])
                dmxpacket.append(clr[2])
            frame.append(dmxpacket)
        frames.append(frame)

    global rngs
    rngs = dmxrngs

    global forward
    forward = True

    global t_idx
    t_idx = 0

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#10
0
def squid(dmxrngs, value):
    global rngs
    rngs = dmxrngs

    global tepilepsy
    tepilepsy = Tepilepsy()

    v = float(value) / 255.0
    global shimmering
    shimmering = Shimmering(tepilepsy, v)

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#11
0
文件: Off.py 项目: aleden/squidlights
def squid(dmxrngs):
    global rngs
    rngs = dmxrngs

    global datas
    datas = []
    for rng in rngs:
        data = array.array('B', [0] * rng[1])
        for chann in range(rng[1], rng[2]):
            data.append(0)
        datas.append(data)

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#12
0
def squid(dmxrngs):
    global rngs
    rngs = dmxrngs

    global tepilepsy
    tepilepsy = Tepilepsy()

    global gen_1
    gen_1 = Image.open('/home/squidlights/resources/gen1.png')
    global gen_2
    gen_2 = Image.open('/home/squidlights/resources/gen2.png')
    global gen_3
    gen_3 = Image.open('/home/squidlights/resources/gen3.png')
    global gen_4
    gen_4 = Image.open('/home/squidlights/resources/gen4.png')
    global gen_5
    gen_5 = Image.open('/home/squidlights/resources/gen5.png')

    # clear first
    for x in range(tepilepsy.GetWidth()):
        for y in range(tepilepsy.GetHeight()):
            tepilepsy.SetPixel((x, y), (0, 0, 0))

    # decide on pokemon index
    idx = random.randint(0, 825)
    # open image, resize to fit
    im = get_pokemon(idx)
    im = im.convert('RGB')
    im.thumbnail((tepilepsy.GetWidth(), tepilepsy.GetHeight()), Image.NEAREST)
    im = im.convert('RGB')
    im.save('/tmp/im.png', 'PNG')

    # set image pixels
    for x in range(im.width):
        for y in range(im.height):
            tepilepsy.SetPixel((x, y), im.getpixel((x, y)))

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#13
0
def squid(dmxrngs, dmx_first, dmx_last):
    global rngs
    rngs = dmxrngs

    dmx_beg = dmx_first - 1
    dmx_end = dmx_last - 1

    global datas
    datas = []
    for rng in rngs:
        data = array.array('B', [0] * 512)
        for chann in range(dmx_beg, dmx_end):
            data[chann] = 255
        datas.append(data)

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#14
0
def squid(dmxrngs, begclr, endclr, delta_t):
    # arrange beginning and ending RGB colors into a matrix
    # which looks like [begclr,
    #                   endclr].
    global colors
    colors = np.vstack((begclr, endclr))

    global period
    period = delta_t

    global half_width
    half_width = period / 2.0

    global rngs
    rngs = dmxrngs

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#15
0
def squid(dmxrngs, pic):
    global rngs
    rngs = dmxrngs

    global tepilepsy
    tepilepsy = Tepilepsy()

    # open image, resize to fit
    im = Image.open(pic)
    im = im.convert('RGB')
    im.thumbnail((tepilepsy.GetWidth(), tepilepsy.GetHeight()))
    im = im.convert('RGB')
    im.save('/tmp/im.png', 'PNG')

    # set image pixels
    for x in range(im.width):
        for y in range(im.height):
            tepilepsy.SetPixel((x, y), im.getpixel((x, y)))

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#16
0
def squid(dmxrngs, gif, period):
    global rngs
    rngs = dmxrngs

    global tick_interval
    tick_interval = period

    im = Image.open(gif)

    global dmxframes
    dmxframes = []

    global idx
    idx = 0

    while True:
        try:
            tepilepsy = Tepilepsy()

            # retrieve pixels for this frame
            for x in range(im.width):
                for y in range(im.height):
                    i = im.getpixel((x, y))
                    clr = im.getpalette()[3*i:3*i+3]
                    tepilepsy.SetPixel((x, y), clr)

            dmxframes.append(tepilepsy.DMXData())

            im.seek(im.tell() + 1)
        except EOFError:
            break # no more frames in animated gif

    global wrapper
    wrapper = ClientWrapper()
    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#17
0
def squid(dmxrngs, t, size):
    global rngs
    rngs = dmxrngs

    global tick_interval
    tick_interval = t

    global tepilepsy
    tepilepsy = Tepilepsy()

    colors = ((255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255), (255, 255, 255))
    i = 0
    for x in range(0, tepilepsy.GetWidth() - (size - 1), size):
        for y in range(0, tepilepsy.GetHeight() - (size - 1), size):
            for j in range(size):
                for k in range(size):
                    tepilepsy.SetPixel((x+j, y+k), colors[i % len(colors)])
            i+=1

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#18
0
    def testBasic(self):
        sockets = socket.socketpair()
        wrapper = ClientWrapper(sockets[0])

        class results:
            a_called = False
            b_called = False

        def a():
            results.a_called = True

        def b():
            results.b_called = True
            wrapper.Stop()

        wrapper.AddEvent(0, a)
        wrapper.AddEvent(0, b)
        self.assertFalse(results.a_called)
        wrapper.Run()
        self.assertTrue(results.a_called)
        self.assertTrue(results.b_called)

        sockets[0].close()
        sockets[1].close()
示例#19
0
    if is_first:
        print("Turning on first set of lights")
        turn_on = first_channels
    else:
        print("Turning on second set of lights")
        turn_on = second_channels

    dmx_data = array('B', [DMX_MIN_SLOT_VALUE] * DMX_UNIVERSE_SIZE)

    for x in turn_on:
        dmx_data[x - 1] = (dmx_data[x - 1] + 100) % 256

    is_first = not is_first

    client.SendDmx(UNIVERSE, dmx_data)
    client_wrapper.AddEvent(UPDATE_INTERVAL, flip)


def stop():
    print("Stopping")
    client_wrapper.Stop()


print("Registering events")
client_wrapper.AddEvent(SHUTDOWN_INTERVAL, stop)
client_wrapper.AddEvent(UPDATE_INTERVAL, flip)

print("Running Wrapper")
client_wrapper.Run()
示例#20
0
def squid(dmxrngs):
    global rngs
    rngs = dmxrngs

    global tepilepsy
    tepilepsy = Tepilepsy()

    pokemon = os.listdir('/home/squidlights/resources/pokered/bmon')
    seen = eval(open('/home/squidlights/build/pokeredseen', 'r').read())
    left = list(set(pokemon) - set(seen))
    if len(left) == 0:
        seen = []
        left = pokemon

    random.seed()
    poke = left[random.randint(0, len(left) - 1)]
    seen.append(poke)
    fpf(open('/home/squidlights/build/pokeredseen', 'w'), seen)

    pals = eval(open('/home/squidlights/resources/pokered/pals', 'r').read())
    pokepal = eval(
        open('/home/squidlights/resources/pokered/pokepal', 'r').read())

    palnm = pokepal[poke]
    pal = pals[palnm]

    #perr(pokemon)
    #perr(pal)

    pixrows = eval(
        open("/home/squidlights/resources/pokered/bmon/%s" % poke, 'r').read())
    w = len(pixrows[0])
    h = len(pixrows)

    #   for row in pixrows:
    #       for i in range(len(row)):
    #           row[i] = 3 - row[i]

    perr(poke)
    #perr(palnm)
    #perr(pixrows)

    #pal[0] = (0,0,0)
    #pal[0] = (255 - pal[0][0], 255 - pal[0][1], 255 - pal[0][2])
    #pal[3] = (255 - pal[3][0], 255 - pal[3][1], 255 - pal[3][2])

    x = pal[0]
    y = pal[3]

    pal[0] = (0, 0, 0)
    pal[3] = x

    im = Image.new("RGB", (w, h))
    for y in range(h):
        for x in range(w):
            im.putpixel((x, y), pal[pixrows[y][x]])

    def inimage(x, y):
        return 0 <= x < im.width and 0 <= y < im.height

    imtmp = im.copy()

    def floodfill(x, y, seedclr, newclr):
        if inimage(x, y):
            tl = (x - 1, y - 1)
            l = (x - 1, y)
            bl = (x - 1, y + 1)

            t = (x, y - 1)
            m = (x, y)
            b = (x, y + 1)

            tr = (x + 1, y - 1)
            r = (x + 1, y)
            br = (x + 1, y + 1)
            if (((not inimage(*tl)) or imtmp.getpixel(tl) == seedclr)
                    and ((not inimage(*l)) or imtmp.getpixel(l) == seedclr)
                    and ((not inimage(*bl)) or imtmp.getpixel(bl) == seedclr)
                    and ((not inimage(*t)) or imtmp.getpixel(t) == seedclr)
                    and ((not inimage(*m)) or imtmp.getpixel(m) == seedclr)
                    and ((not inimage(*b)) or imtmp.getpixel(b) == seedclr)
                    and ((not inimage(*tr)) or imtmp.getpixel(tr) == seedclr)
                    and ((not inimage(*r)) or imtmp.getpixel(r) == seedclr)
                    and ((not inimage(*br)) or imtmp.getpixel(br) == seedclr)):
                if (inimage(*tl)):
                    im.putpixel(tl, newclr)
                if (inimage(*l)):
                    im.putpixel(l, newclr)
                if (inimage(*bl)):
                    im.putpixel(bl, newclr)
                if (inimage(*t)):
                    im.putpixel(t, newclr)
                if (inimage(*m)):
                    im.putpixel(m, newclr)
                if (inimage(*b)):
                    im.putpixel(b, newclr)
                if (inimage(*tr)):
                    im.putpixel(tr, newclr)
                if (inimage(*r)):
                    im.putpixel(r, newclr)
                if (inimage(*br)):
                    im.putpixel(br, newclr)

                floodfill(x - 1, y, seedclr, newclr)
                floodfill(x + 1, y, seedclr, newclr)
                floodfill(x, y - 1, seedclr, newclr)
                floodfill(x, y + 1, seedclr, newclr)

    seedclr = (0, 0, 0)
    ImageDraw.floodfill(im, (0, 0), seedclr)
    ImageDraw.floodfill(im, (im.width - 1, 0), seedclr)
    ImageDraw.floodfill(im, (0, im.height - 1), seedclr)
    ImageDraw.floodfill(im, (im.width - 1, im.height - 1), seedclr)

    ##floodfill(0, 0, seedclr, (0, 0, 0))

    # |---
    # |
    # |
    # |
    # |
    #x = 0
    #for y in range(im.height):
    #floodfill(x, y, seedclr, (0, 0, 0))

    # ---|
    #    |
    #    |
    #    |
    #    |
    #x = im.width - 1
    #for y in range(im.height):
    #floodfill(x, y, seedclr, (0, 0, 0))

    # |--------------
    # |
    # |
    #y = 0
    #for x in range(im.width):
    #floodfill(x, y, seedclr, (0, 0, 0))

    # |
    # |
    # |--------------
    #y = im.height - 1
    #for x in range(im.width):
    #floodfill(x, y, seedclr, (0, 0, 0))

    #im.thumbnail((tepilepsy.GetWidth(), tepilepsy.GetHeight()), Image.LANCZOS)

    # set background color
    #for x in range(tepilepsy.GetWidth()):
    #    for y in range(tepilepsy.GetHeight()):
    #        tepilepsy.SetPixel((x, y), pal[0])

    # center vertically?
    yoff = 0
    #if im.height - im.height / 4 >= tepilepsy.GetHeight():
    #    yoff = -im.height / 4

    # for each horizontal row of pixels from the top, add -1 to the yoff
    #   allblackrows = [all(elem == pal[0] for elem in l) for l in poke]
    #   for y in range(len(allblackrows)):
    #       if allblackrows[y] == False:
    #           break
    #       yoff = -y

    # center horizontally?
    xoff = 0
    if im.width < tepilepsy.GetWidth():
        xoff = (tepilepsy.GetWidth() / 2) - (im.width / 2)

    # center vertically?
    yoff = 0
    for y in xrange(im.height):
        if all(im.getpixel((x, y)) == (0, 0, 0) for x in xrange(im.width)):
            yoff -= 1
        else:
            break

#   if im.height < tepilepsy.GetHeight():
#       yoff = (tepilepsy.GetHeight() / 2) - (im.height / 2)

#   for x in range(im.width):
#       for y in range(im.height):
#           tepilepsy.SetPixel((x, y), seedclr)

# set image pixels
    for x in range(im.width):
        for y in range(im.height):
            tepilepsy.SetPixel((x + xoff, y + yoff), im.getpixel((x, y)))

    global wrapper
    wrapper = ClientWrapper()

    wrapper.AddEvent(22, SendDMXFrame)
    wrapper.Run()
示例#21
0
class Controller:
    def __init__(self, config, inputdevice):
        self.config = config
        self.current_frame = [0] * 512
        self.scene_updated = False
        self.input_device = InputDevice(inputdevice)
        self.wrapper = ClientWrapper()
        self.current_scene = self.config["scenes"][self.config["start_scene"] -
                                                   1]
        self.nextStep(True)

    """ start dmx transmission """

    def run(self):
        self.wrapper.AddEvent(self.config["frame_duration"], self.nextFrame)
        self.wrapper.Run()

    """ calculate the dmx values for a new frame and send the frame """

    def nextFrame(self):
        #starttime = datetime.datetime.now()
        self.wrapper.AddEvent(self.config["frame_duration"], self.nextFrame)
        self.handleKeypress()

        if self.fade_frames > 0:
            # interpolate dmx values during a fade
            for i in range(
                    len(self.current_scene["steps"][self.next_step]
                        ["values"])):
                self.current_frame[i] = int(
                    round(self.current_frame[i] +
                          float(self.current_scene["steps"][self.next_step]
                                ["values"][i] - self.current_frame[i]) /
                          self.fade_frames))
            self.fade_frames -= 1
        else:
            # no fade, copy dmx values from scene if necessary
            if not self.scene_updated:
                for i in range(
                        len(self.current_scene["steps"][self.next_step]
                            ["values"])):
                    self.current_frame[i] = self.current_scene["steps"][
                        self.next_step]["values"][i]
                self.scene_updated = True
            if self.hold_frames > 0:
                self.hold_frames -= 1
            else:
                self.nextStep()

        data = array.array('B', self.current_frame)
        self.wrapper.Client().SendDmx(self.config["universe"], data)
        #delta = datetime.datetime.now() - starttime
        #print("Time spent: %d microseconds" % delta.microseconds)

    """ check if user pressed a key and try to match keypress to a scene """

    def handleKeypress(self):
        a, b, c = select([self.input_device], [], [],
                         0)  # wait until we can read
        if not a:
            return
        for event in self.input_device.read():
            # only track key down events
            if event.type == ecodes.EV_KEY and event.value == 1:
                if event.code == 16:
                    # q pressed => quit
                    self.wrapper.Stop()
                else:
                    # iterate over all scenes and check if a key_trigger
                    # matches current keypress
                    action_triggered = False
                    for scene in self.config["scenes"]:
                        if event.code in scene["trigger_keys"]:
                            self.current_scene = scene
                            self.nextStep(True)
                            action_triggered = True
                            break
                    if action_triggered == False:
                        print("Unmapped key code: %d" % event.code)

    """ progress to the next step in a scene """

    def nextStep(self, newScene=False):
        if newScene == True:
            self.next_step = 0
        else:
            if self.current_scene["order"] == "random":
                step = randint(0, len(self.current_scene["steps"]) - 1)
                while step == self.next_step:
                    step = randint(0, len(self.current_scene["steps"]) - 1)
                self.next_step = step
            else:
                if self.next_step < (len(self.current_scene["steps"]) - 1):
                    self.next_step += 1
                elif self.current_scene["repeat"] == True:
                    self.next_step = 0
                else:
                    return
        self.scene_updated = False
        self.hold_frames = int(
            round(self.current_scene["steps"][self.next_step]["hold"] /
                  self.config["frame_duration"])) + 1
        self.fade_frames = int(
            round(self.current_scene["steps"][self.next_step]["fade"] /
                  self.config["frame_duration"]))
        print('Playing scene: %-30s Step: %02d/%02d' %
              (self.current_scene["name"], self.next_step + 1,
               len(self.current_scene["steps"])))
示例#22
0
class InteractiveModeController(cmd.Cmd):
  """Interactive mode!"""
  def __init__(self, universe, uid, sub_device, pid_location):
    """Create a new InteractiveModeController.

    Args:
      universe:
      uid:
      sub_device:
      pid_location:
    """
    cmd.Cmd.__init__(self)
    self._universe = universe
    self._uid = uid
    self._sub_device = sub_device
    self.pid_store = PidStore.GetStore(pid_location)
    self.wrapper = ClientWrapper()
    self.client = self.wrapper.Client()
    self.rdm_api = RDMAPI(self.client, self.pid_store)
    self._uids = []
    self._response_printer = ResponsePrinter()

    # tuple of (sub_device, command_class, pid)
    self._outstanding_request = None

    self.prompt = '> '

  def emptyline(self):
    pass

  def do_exit(self, s):
    """Exit the interpreter."""
    return True

  def do_EOF(self, s):
    print('')
    return self.do_exit('')

  def do_uid(self, line):
    """Sets the active UID."""
    args = line.split()
    if len(args) != 1:
      print('*** Requires a single UID argument')
      return

    uid = UID.FromString(args[0])
    if uid is None:
      print('*** Invalid UID')
      return

    if uid not in self._uids:
      print('*** UID not found')
      return

    self._uid = uid
    print('Fetching queued messages...')
    self._FetchQueuedMessages()
    self.wrapper.Run()

  def complete_uid(self, text, line, start_index, end_index):
    tokens = line.split()
    if len(tokens) > 1 and text == '':
      return []

    uids = [str(uid) for uid in self._uids if str(uid).startswith(text)]
    return uids

  def do_subdevice(self, line):
    """Sets the sub device."""
    args = line.split()
    if len(args) != 1:
      print('*** Requires a single int argument')
      return

    try:
      sub_device = int(args[0])
    except ValueError:
      print('*** Requires a single int argument')
      return

    if sub_device < 0 or sub_device > PidStore.ALL_SUB_DEVICES:
      print('*** Argument must be between 0 and 0x%hx' %
            PidStore.ALL_SUB_DEVICES)
      return
    self._sub_device = sub_device

  def do_print(self, line):
    """Prints the current universe, UID and sub device."""
    print(textwrap.dedent("""\
      Universe: %d
      UID: %s
      Sub Device: %d""" % (
        self._universe,
        self._uid,
        self._sub_device)))

  def do_uids(self, line):
    """List the UIDs for this universe."""
    self.client.FetchUIDList(self._universe, self._DisplayUids)
    self.wrapper.Run()

  def _DisplayUids(self, state, uids):
    self._uids = []
    if state.Succeeded():
      self._UpdateUids(uids)
      for uid in uids:
        print(str(uid))
    self.wrapper.Stop()

  def do_full_discovery(self, line):
    """Run full RDM discovery for this universe."""
    self.client.RunRDMDiscovery(self._universe, True, self._DiscoveryDone)
    self.wrapper.Run()

  def do_incremental_discovery(self, line):
    """Run incremental RDM discovery for this universe."""
    self.client.RunRDMDiscovery(self._universe, False, self._DiscoveryDone)
    self.wrapper.Run()

  def _DiscoveryDone(self, state, uids):
    if state.Succeeded():
      self._UpdateUids(uids)
    self.wrapper.Stop()

  def _UpdateUids(self, uids):
    self._uids = []
    for uid in uids:
      self._uids.append(uid)

  def do_list(self, line):
    """List the pids available."""
    names = []
    for pid in self.pid_store.Pids():
      names.append('%s (0x%04hx)' % (pid.name.lower(), pid.value))
    if self._uid:
      for pid in self.pid_store.ManufacturerPids(self._uid.manufacturer_id):
        names.append('%s (0x%04hx)' % (pid.name.lower(), pid.value))
    names.sort()
    print('\n'.join(names))

  def do_queued(self, line):
    """Fetch all the queued messages."""
    self._FetchQueuedMessages()
    self.wrapper.Run()

  def do_get(self, line):
    """Send a GET command."""
    self.GetOrSet(PidStore.RDM_GET, line)

  def complete_get(self, text, line, start_index, end_index):
    return self.CompleteGetOrSet(PidStore.RDM_GET, text, line)

  def do_set(self, line):
    """Send a SET command."""
    self.GetOrSet(PidStore.RDM_SET, line)

  def complete_set(self, text, line, start_index, end_index):
    return self.CompleteGetOrSet(PidStore.RDM_SET, text, line)

  def CompleteGetOrSet(self, request_type, text, line):
    if len(line.split(' ')) > 2:
      return []
    pids = [pid for pid in self.pid_store.Pids()
            if pid.name.lower().startswith(text)]
    if self._uid:
      for pid in self.pid_store.ManufacturerPids(self._uid.manufacturer_id):
        if pid.name.lower().startswith(text):
          pids.append(pid)

    # now check if this type of request is supported
    pid_names = sorted([pid.name.lower() for pid in pids
                        if pid.RequestSupported(request_type)])

    return pid_names

  def GetOrSet(self, request_type, line):
    if self._uid is None:
      print('*** No UID selected, use the uid command')
      return

    args = line.split()
    command = 'get'
    if request_type == PidStore.RDM_SET:
      command = 'set'
    if len(args) < 1:
      print('%s <pid> [args]' % command)
      return

    pid = None
    try:
      pid = self.pid_store.GetPid(int(args[0], 0), self._uid.manufacturer_id)
    except ValueError:
      pid = self.pid_store.GetName(args[0].upper(), self._uid.manufacturer_id)
    if pid is None:
      print('*** Unknown pid %s' % args[0])
      return

    if not pid.RequestSupported(request_type):
      print('*** PID does not support command')
      return

    if request_type == PidStore.RDM_SET:
      method = self.rdm_api.Set
    else:
      method = self.rdm_api.Get

    try:
      if method(self._universe,
                self._uid,
                self._sub_device,
                pid,
                self._RDMRequestComplete,
                args[1:]):
        self._outstanding_request = (self._sub_device, request_type, pid)
        self.wrapper.Run()
    except PidStore.ArgsValidationError as e:
      args, help_string = pid.GetRequestDescription(request_type)
      print('Usage: %s %s %s' % (command, pid.name.lower(), args))
      print(help_string)
      print('')
      print('*** %s' % e)
      return

  def _FetchQueuedMessages(self):
    """Fetch messages until the queue is empty."""
    pid = self.pid_store.GetName('QUEUED_MESSAGE', self._uid.manufacturer_id)
    self.rdm_api.Get(self._universe,
                     self._uid,
                     PidStore.ROOT_DEVICE,
                     pid,
                     self._QueuedMessageComplete,
                     ['error'])

  def _RDMRequestComplete(self, response, unpacked_data, unpack_exception):
    if not self._CheckForAckOrNack(response):
      return

    # at this stage the response is either a ack or nack
    self._outstanding_request = None
    self.wrapper.Stop()

    if response.response_type == OlaClient.RDM_NACK_REASON:
      print('Got nack with reason: %s' % response.nack_reason)
    elif unpack_exception:
      print(unpack_exception)
    else:
      self._response_printer.PrintResponse(self._uid, response.pid,
                                           unpacked_data)

    if response.queued_messages:
      print('%d queued messages remain' % response.queued_messages)

  def _QueuedMessageComplete(self, response, unpacked_data, unpack_exception):
    if not self._CheckForAckOrNack(response):
      return

    if response.response_type == OlaClient.RDM_NACK_REASON:
      if (self._outstanding_request and
          response.sub_device == self._outstanding_request[0] and
          response.command_class == self._outstanding_request[1] and
          response.pid == self._outstanding_request[2].value):
        # we found what we were looking for
        self._outstanding_request = None
        self.wrapper.StopIfNoEvents()

      elif (response.nack_reason == RDMNack.NR_UNKNOWN_PID and
            response.pid == self.pid_store.GetName('QUEUED_MESSAGE').value):
        print('Device doesn\'t support queued messages')
        self.wrapper.StopIfNoEvents()
      else:
        print('Got nack for 0x%04hx with reason: %s' % (
            response.pid, response.nack_reason))

    elif unpack_exception:
      print('Invalid Param data: %s' % unpack_exception)
    else:
      status_messages_pid = self.pid_store.GetName('STATUS_MESSAGES')
      if (response.pid == status_messages_pid.value and
          unpacked_data.get('messages', []) == []):
        self.wrapper.StopIfNoEvents()
        return

      self._response_printer.PrintResponse(self._uid,
                                           response.pid,
                                           unpacked_data)

    if response.queued_messages:
      self._FetchQueuedMessages()
    else:
      self.wrapper.StopIfNoEvents()

  def _CheckForAckOrNack(self, response):
    """Check for all the different error conditions.

    Returns:
      True if this response was an ACK or NACK, False for all other cases.
    """
    if not response.status.Succeeded():
      print(response.status.message)
      self.wrapper.Stop()
      return False

    if response.response_code != OlaClient.RDM_COMPLETED_OK:
      print(response.ResponseCodeAsString())
      self.wrapper.Stop()
      return False

    if response.response_type == OlaClient.RDM_ACK_TIMER:
      # schedule the fetch
      self.wrapper.AddEvent(response.ack_timer, self._FetchQueuedMessages)
      return False

    return True
示例#23
0
        shouldBe = round(prevSetting + (difference * progress))
        currently = GLOBAL_SEND[int(channel['channel'])]
        if currently > shouldBe:
          GLOBAL_SEND[int(channel['channel'])] = max(min(currently - 1, DMX_MAX_SLOT_VALUE), DMX_MIN_SLOT_VALUE)
          print("Updating {} to {}".format(channel['channel'], GLOBAL_SEND[int(channel['channel'])]))
        elif currently < shouldBe:
          GLOBAL_SEND[int(channel['channel'])] = max(min(currently + 1, DMX_MAX_SLOT_VALUE), DMX_MIN_SLOT_VALUE)
          print("Updating {} to {}".format(channel['channel'], GLOBAL_SEND[int(channel['channel'])]))
        break
      prevKey = key
  WRAPPER.AddEvent(CALC_INTERVAL, calculate)
    
print("Starting...")
GLOBAL_SEND = FULLOFF
try:
  with open(DATASTORE, "r") as f:
    GLOBAL_SEND = json.load(f)
    print("Happy data: {}".format(GLOBAL_SEND))
except:
  pass

GLOBAL_CONFIG = [0,0]
WRAPPER = ClientWrapper()

WRAPPER.AddEvent(SEND_INTERVAL, sendDMX)
WRAPPER.AddEvent(CALC_INTERVAL, calculate)
WRAPPER.Client().RegisterUniverse(UNIVERSE, WRAPPER.Client().REGISTER, receiveData)

# Kick it all off
WRAPPER.Run()
示例#24
0
  def __init__(self, universe, update_interval, client_wrapper,
               dmx_data_size=DMX_UNIVERSE_SIZE):
    dmx_data_size = min(dmx_data_size, DMX_UNIVERSE_SIZE)
    self._universe = universe
    self._update_interval = update_interval
    self._data = array('B', [DMX_MIN_SLOT_VALUE] * dmx_data_size)
    self._wrapper = client_wrapper
    self._client = client_wrapper.Client()
    self._wrapper.AddEvent(self._update_interval, self.UpdateDmx)

  def UpdateDmx(self):
    """
    This function gets called periodically based on UPDATE_INTERVAL
    """
    for i in range(len(self._data)):
      self._data[i] = (self._data[i] + 1) % DMX_MAX_SLOT_VALUE
    # Send the DMX data
    self._client.SendDmx(self._universe, self._data)
    # For more information on Add Event, reference the OlaClient
    # Add our event again so it becomes periodic
    self._wrapper.AddEvent(self._update_interval, self.UpdateDmx)

if __name__ == '__main__':
  wrapper = ClientWrapper()
  controller = SimpleFadeController(UNIVERSE, UPDATE_INTERVAL, wrapper,
                                    DMX_DATA_SIZE)
  # Call it initially
  wrapper.AddEvent(SHUTDOWN_INTERVAL, wrapper.Stop)
  # Start the wrapper
  wrapper.Run()
示例#25
0
class DmxSender(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.Terminated = False
#        self.term=term

## Stop the thread if called

    def stop(self):
        self.Terminated = True

    def run(self):
        '''Wrapper, Framerate'''

        print "THREAD"

        self._wrapper = ClientWrapper()
        self._activesender = True
        self.univloglevel = 0
        self.base = com_sql.ComSql()

        # SQL Framerate
        try:
            engine = self.base.requete_sql(
                "SELECT * FROM dmx_engine WHERE id=1")  #setting
            for e in range(len(engine)):
                freq_ms = engine[e]['freq_ms']
        except:
            print "default to 40 fps"
            freq_ms = 25

        # FOR TEST
#        freq_ms = 500

        self._tick_interval = int(freq_ms)  # in milliseconds

        print "freq_ms"
        print self._tick_interval

        # list of scens to play
        self.scen_ids = []

        # dict to store each scenari instance
        self.my_scens = {}

        # SQL Universes
        try:
            prefs = self.base.requete_sql(
                "SELECT * FROM dmx_preferences WHERE id=1")  #setting
            for p in range(len(prefs)):
                self.univ_qty = prefs[p]['univ_qty']
        except:
            print "default to 1 universe"
            self.univ_qty = 1

        print "univ_qty"
        print self.univ_qty

        # array to store full frame
        self.WholeDmxFrame = [0] * 512 * self.univ_qty

        # send the first one
        self.SendDmxFrame()
        self._wrapper.Run()

    def BlackOut(self):
        '''Reset all values to zero'''
        self.WholeDmxFrame = [0] * 512 * self.univ_qty

    def AssignChannels(self, offset, values):
        '''Assign channels values according to address'''
        self.WholeDmxFrame[offset:offset + len(values)] = values

    def SendDmxFrame(self):
        '''Ask frame for each scenari and make the whole frame, repeated every tick_interval'''

        if self._activesender:
            # Schedule an event to run in the future
            if self.univloglevel > 0:
                print "Schedule next"
            self._wrapper.AddEvent(self._tick_interval, self.SendDmxFrame)

        if self.univloglevel > 1:
            print "before sending   %s" % time.time()

        # send data to universes
#        print "SPLIT"
        SplittedFrame = self.USplit(self.WholeDmxFrame, 512)

        u = 1
        for FramePart in SplittedFrame:
            UniverseFrame = list(FramePart)
            if self.univloglevel > 0:
                print "FRAME_FOR_UNIV %s" % u
#               print UniverseFrame
            try:
                data = array.array('B', UniverseFrame)
                self._wrapper.Client().SendDmx(u, data)
            except:
                print "Dmx frame not sent. Reset all."
                self.ResetAll()
            u += 1

        if self.univloglevel > 1:
            print "before computing %s" % time.time()

        #for each scenari in list
        for scenarid in self.scen_ids:
            try:
                # create scenari instance if needed
                if not self.my_scens.has_key(scenarid):
                    scen = PlayScenari(scenarid, self._tick_interval)

                    # store instance in dict, only once
                    self.my_scens[scenarid] = scen
                    print self.my_scens

                # for each instance, compute frame
                scen = self.my_scens[scenarid]
                scen.ComputeNextFrame()
                #               print "calling %s" % scen.new_frame

                # add partial frame to full one
                self.AssignChannels(scen.patch, scen.new_frame)

#                print "FRAME"
#                print self.WholeDmxFrame
            except:
                print "NOT STARTED"

        if self.univloglevel > 1:
            print "after computing  %s" % time.time()
            print "---"

    def ChangeUnivLogLevel(self):
        self.univloglevel += 1
        if self.univloglevel > 2:
            self.univloglevel = 0
            return False
        else:
            return True

    def ChangeLogLevel(self, scenarid):
        if self.my_scens.has_key(scenarid):
            # set loglevel for this instance
            scen = self.my_scens[scenarid]
            print scen
            scen.loglevel += 1
            if scen.loglevel > 2:
                scen.loglevel = 0
                return False
            else:
                return True

    def HaltDmxSender(self):
        if self._activesender == True:
            self._activesender = False
            return True

    def ResumeDmxSender(self):
        if self._activesender == False:
            self._activesender = True
            self.SendDmxFrame()
            return True

    def CloseDmxSender(self):
        self._wrapper.Stop()

    def StartScenari(self, scenarid):
        if not scenarid in self.scen_ids:
            # add id into list
            self.scen_ids.append(scenarid)
            return True

    def StopScenari(self, scenarid):
        if scenarid in self.scen_ids:
            # remove id into list
            self.scen_ids.remove(scenarid)
            return True

    def StatusScenari(self, scenarid):
        if scenarid in self.scen_ids:
            return True

    def ResetScenari(self, scenarid):
        if self.my_scens.has_key(scenarid):
            # remove instance for this id
            self.my_scens.pop(scenarid)
            return True

    def StopAll(self):
        self.scen_ids = []

    def ResetAll(self):
        self.my_scens = {}

    def USplit(self, l, n):
        return zip(*(l[i::n] for i in range(n)))
示例#26
0
    def testEventLoop(self):
        sockets = socket.socketpair()
        wrapper = ClientWrapper(sockets[0])

        class results:
            a_called = None
            b_called = None
            c_called = None
            d_called = None

        def a():
            self.assertIsNone(results.a_called)
            self.assertIsNone(results.b_called)
            self.assertIsNone(results.c_called)
            self.assertIsNone(results.d_called)
            results.a_called = datetime.datetime.now()

        def b():
            self.assertIsNotNone(results.a_called)
            self.assertIsNone(results.b_called)
            self.assertIsNone(results.c_called)
            self.assertIsNone(results.d_called)
            results.b_called = datetime.datetime.now()

        def c():
            self.assertIsNotNone(results.a_called)
            self.assertIsNotNone(results.b_called)
            self.assertIsNone(results.c_called)
            self.assertIsNone(results.d_called)
            results.c_called = datetime.datetime.now()

        def d():
            self.assertIsNotNone(results.a_called)
            self.assertIsNotNone(results.b_called)
            self.assertIsNotNone(results.c_called)
            self.assertIsNone(results.d_called)
            results.d_called = datetime.datetime.now()
            wrapper.AddEvent(0, wrapper.Stop)

        self.start = datetime.datetime.now()
        wrapper.AddEvent(0, a)
        wrapper.AddEvent(15, d)
        wrapper.AddEvent(datetime.timedelta(milliseconds=5), b)
        wrapper.AddEvent(10, c)

        self.assertIsNone(results.a_called)
        self.assertIsNone(results.b_called)
        self.assertIsNone(results.c_called)
        self.assertIsNone(results.d_called)

        self.start = datetime.datetime.now()
        wrapper.Run()

        self.assertIsNotNone(results.a_called)
        self.assertIsNotNone(results.b_called)
        self.assertIsNotNone(results.c_called)
        self.assertIsNotNone(results.d_called)

        self.assertTrue(
            results.a_called - self.start < datetime.timedelta(milliseconds=5))
        self.assertTrue(results.b_called -
                        self.start >= datetime.timedelta(milliseconds=5))
        self.assertTrue(results.c_called -
                        self.start >= datetime.timedelta(milliseconds=10))
        self.assertTrue(results.d_called -
                        self.start >= datetime.timedelta(milliseconds=15))

        sockets[0].close()
        sockets[1].close()
示例#27
0
TICK_INTERVAL = 40  # in ms (40 == 25fps)

def DmxSent(state):
  if not state.Succeeded():
    wrapper.Stop()

def SendDMXFrame():
  # schdule a function call in 100ms
  # we do this first in case the frame computation takes a long time.
  wrapper.AddEvent(TICK_INTERVAL, SendDMXFrame)

  # compute frame here
  data = array.array('B')
  global loop_count
  val1 = loop_count % 50
  val2 = loop_count % 100
  print "val", val1, val2
  data.append(val1)
  data.append(val1)
  data.append(val1)
  data.append(val2)
  data.append(val2)
  data.append(val2)
  loop_count += 4

  # send
  wrapper.Client().SendDmx(1, data, DmxSent)

wrapper = ClientWrapper()
wrapper.AddEvent(TICK_INTERVAL, SendDMXFrame)
wrapper.Run()
class Main:
    def __init__(self):
        self.settings = yaml.load(open('settings.yaml', 'r'))
        self.serv = sockethandler.server(self.settings.get('address') or 'localhost', self.settings.get('port') or 25500)
        self.clients = {}
        self.timers = {}

        self.locked = False
        self.passcode = self.settings['passcode']

        self.defaults = self.settings['defaults']

        self.universes = {}
        self.switches = {}
        for s in self.settings['switches'].items():
            switch = Switch(s[0], s[1], self.defaults)
            if not self.universes.get(switch.universe):
                self.universes[switch.universe] = array.array('B', [0] * 512)
                
            self.switches[s[0]] = switch

        self.wrapper = ClientWrapper()
        self.wrapper.AddEvent(100, self.loop)

    def send_status(self, clients):
        status = {}
        status['sw'] = [s.json() for s in self.switches.values()]
        status['l'] = [self.passcode, self.locked]
        status['t'] = [[t.id, t.time, t.action, t.lock] for t in self.timers.values()]
        for client in clients:
            self.serv.send(['s', status], client.addr)

    def loop(self):
        self.wrapper.AddEvent(100, self.loop)
        send_update = False
        for msg, addr in self.serv.recv():
            if self.settings.get('debug'): print(msg, addr)
            if not self.clients.get(addr):
                self.clients[addr] = Client(addr)
                print('client ' + str(addr) + ' connected')

            client = self.clients[addr]

            if msg[0] == 'hi':
                self.send_status([client])

            if msg[0] == 'hb':
                client.lasthb = time.time()
                
            elif msg[0] == 'set':
                if self.locked: self.send_status([client])
                else:
                    self.switches[msg[1]].set(msg[2])
                    send_update = True
                    
            elif msg[0] == 'lock':
                print('locked by client: ', client.addr)
                self.locked = True
                send_update = True

            elif msg[0] == 'unlock':
                print('unlocked by client: ', client.addr)
                self.locked = False
                send_update = True

            elif msg[0] == 'timer':
                print('timer set:', msg[1:])
                timer = Timer(msg[1], msg[2], msg[3], self)
                self.timers[timer.id] = timer
                send_update = True

            elif msg[0] == 'cancel_timer':
                print('timer canceled:', msg[1:])
                try: del self.timers[msg[1]]
                except KeyError: pass
                send_update = True

            elif msg[0] == 'bye':
                print('client ' + str(addr) + ' disconnected')
                del self.clients[addr]

        curr_universes = {u[0]: array.array('B', u[1]) for u in self.universes.items()}
        msg = ['sw']

        for switch in self.switches.values():
            addrs, vals = switch.tick()
            for addr in addrs:
                curr_universes[switch.universe][addr-1] = vals[addrs.index(addr)]

        for timer in self.timers.values():
            if timer.check():
                del self.timers[timer.id]
                send_update = True

        for client in self.clients.values():
            if time.time() - client.lasthb > 0.5:
                self.serv.send(['hb'], client.addr)

            if time.time() - client.lasthb > 2:
                print('client ' + str(client.addr) + ' timed out')
                del self.clients[client.addr]

        if not curr_universes == self.universes:
            send_update = True
            for universe in curr_universes.items():
                self.wrapper.Client().SendDmx(universe[0], universe[1], self.DmxSent)
            self.universes = curr_universes

        if send_update:
            self.send_status(self.clients.values())

    def DmxSent(self, state):
        if not state.Succeeded():
            wrapper.Stop()
示例#29
0
  def testEventLoop(self):
    sockets = socket.socketpair()
    wrapper = ClientWrapper(sockets[0])

    class results:
      a_called = None
      b_called = None
      c_called = None
      d_called = None

    def a():
      self.assertIsNone(results.a_called)
      self.assertIsNone(results.b_called)
      self.assertIsNone(results.c_called)
      self.assertIsNone(results.d_called)
      results.a_called = datetime.datetime.now()

    def b():
      self.assertIsNotNone(results.a_called)
      self.assertIsNone(results.b_called)
      self.assertIsNone(results.c_called)
      self.assertIsNone(results.d_called)
      results.b_called = datetime.datetime.now()

    def c():
      self.assertIsNotNone(results.a_called)
      self.assertIsNotNone(results.b_called)
      self.assertIsNone(results.c_called)
      self.assertIsNone(results.d_called)
      results.c_called = datetime.datetime.now()

    def d():
      self.assertIsNotNone(results.a_called)
      self.assertIsNotNone(results.b_called)
      self.assertIsNotNone(results.c_called)
      self.assertIsNone(results.d_called)
      results.d_called = datetime.datetime.now()
      wrapper.AddEvent(0, wrapper.Stop)

    self.start = datetime.datetime.now()
    wrapper.AddEvent(0, a)
    wrapper.AddEvent(15, d)
    wrapper.AddEvent(datetime.timedelta(milliseconds=5), b)
    wrapper.AddEvent(10, c)

    # Nothing has been called yet
    self.assertIsNone(results.a_called)
    self.assertIsNone(results.b_called)
    self.assertIsNone(results.c_called)
    self.assertIsNone(results.d_called)

    self.start = datetime.datetime.now()
    wrapper.Run()

    # Everything has been called
    self.assertIsNotNone(results.a_called)
    self.assertIsNotNone(results.b_called)
    self.assertIsNotNone(results.c_called)
    self.assertIsNotNone(results.d_called)

    # Check when the callbacks were called. Allow 500 microseconds of drift.
    # Called immediately
    a_diff = results.a_called - self.start
    self.assertAlmostEqual(a_diff, datetime.timedelta(milliseconds=0),
                           delta=datetime.timedelta(microseconds=500))

    # Called in 5 milliseconds
    b_diff = results.b_called - self.start
    self.assertAlmostEqual(b_diff, datetime.timedelta(milliseconds=5),
                           delta=datetime.timedelta(microseconds=500))

    # Called in 10 milliseconds
    c_diff = results.c_called - self.start
    self.assertAlmostEqual(c_diff, datetime.timedelta(milliseconds=10),
                           delta=datetime.timedelta(microseconds=500))

    # Called in 15 milliseconds
    d_diff = results.d_called - self.start
    self.assertAlmostEqual(d_diff, datetime.timedelta(milliseconds=15),
                           delta=datetime.timedelta(microseconds=500))

    sockets[0].close()
    sockets[1].close()
示例#30
0
class Midi2Dmx(threading.Thread):
    def __init__(self, driver_name="DMX Bridge", universe=0):
        """ midi->dmx bridge
        :param driver_name:  The midi name of the bridge. This will
                      show up in Logic
        :param universe:    The DMX universe to connect to
        """

        self.driver_name = driver_name
        self.appname = "{} - {}".format(__appname__, driver_name)
        # initialize a default dmx frame

        self.midi_source = MIDIDestination(driver_name)

        self.frame = [0] * 255
        self.universe = universe

        # this is the starting note for all midi channels
        self.note_offset = 24

        # this is the number of dmx channels per midi channel
        # each midi channel will support 32 notes. This will allow
        # 16 fixtures via 16 midi channels.
        self.dmx_offset = 32

        # MacOS X related stuff

        self.NSUserNotification = objc.lookUpClass('NSUserNotification')
        self.NSUserNotificationCenter = objc.lookUpClass(
            'NSUserNotificationCenter')

        self.dmx_wrapper = None
        self.dmx_client = None
        self.dmx_tick = 100
        self.midi_tick = 10
        super(Midi2Dmx, self).__init__()

    def run(self):
        """Start up the service safely"""
        self.initialize()
        if self.dmx_wrapper:
            self.dmx_wrapper.Run()

    def stop(self):
        """Stop the service safely"""
        if self.dmx_wrapper:
            self.notify(
                "Stopping...", "Stopping the DMX Bridge. Midi Events "
                "will NOT be sent to the DMX device")
            self.dmx_wrapper.Stop()
        else:
            self.notify("DMX is not running",
                        "Stop command issued to an inactive "
                        "DMX bridge.")

    def initialize(self):
        """
        Zero out dmx, set up events
        """
        try:
            self.dmx_wrapper = ClientWrapper()
            self.dmx_client = self.dmx_wrapper.Client()
        except:
            self.notify(
                "OLAD is not running", "Attept to connect to OLAD failed. "
                "Please start it and try again.")
            return

        self.dmx_wrapper.AddEvent(self.dmx_tick, self.send_to_dmx)
        self.dmx_wrapper.AddEvent(self.dmx_tick / 2, self.get_midi_data)

    def notify(self, subtitle, info_text):
        """Send an os x  notification"""
        title = "{} - Universe {}".format(self.appname, self.universe)
        rumps.notification(title, subtitle, info_text, sound=False)

    def dmx_frame_sent(self, state):
        """SendDMX callback"""
        if not state.Succeeded():
            self.dmx_wrapper.Stop()

    def send_to_dmx(self):
        """Send the frame to the uDMX device"""

        self.dmx_wrapper.AddEvent(self.dmx_tick, self.send_to_dmx)
        dmx_frame = self.build_dmx_frame()
        self.dmx_client.SendDmx(self.universe, dmx_frame, self.dmx_frame_sent)

    def update_frame(self, channel, note, velocity):
        """Translate midi note to dmx channel and
           velocity to value"""
        value = velocity * 2
        dmx_channel = (note - self.note_offset) + (
            (channel - 1) * self.dmx_offset)
        self.frame[dmx_channel] = value

    def build_dmx_frame(self):
        """Translate our internal frame structure into a proper dmx frame"""

        dmx_frame = array.array("B")
        for frame_channel in self.frame:
            dmx_frame.append(frame_channel)
        return dmx_frame

    def get_midi_data(self):
        """Get midi data from the midi source"""

        self.dmx_wrapper.AddEvent(self.dmx_tick, self.get_midi_data)
        midi_data = self.midi_source.recv()
        if len(midi_data) > 0:
            print midi_data
        for s in split_seq(midi_data, 3):
            self.parse_midi_data(s)

    def parse_midi_data(self, midi_data):
        """Parse the midi data"""

        # we're going to ignore non-note traffic
        # sysex data and such.
        note_on = False
        modifier = 0
        midi_channel = midi_data[0]

        if midi_channel in range(144, 159):
            modifier = 143
            note_on = True

        if midi_channel in range(128, 143):
            modifier = 127
            note_on = False

        if midi_channel in range(144, 159) or midi_channel in range(128, 143):

            channel = midi_channel - modifier
            note = midi_data[1]
            # make sure our velocity is '0' for the note-off
            # event.
            if note_on:
                velocity = midi_data[2]
            else:
                velocity = 0
            self.update_frame(channel, note, velocity)