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()
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()
def start_wrapper(): global wrapper global client wrapper = ClientWrapper() client = wrapper.Client() wrapper.AddEvent(0, main_loop) wrapper.Run()
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()
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
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()
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()
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")
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()
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()
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()
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()
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()
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()
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()
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()
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()
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()
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()
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()
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"])))
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
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()
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()
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)))
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()
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()
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()
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)