Exemple #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()
Exemple #2
0
class OlaThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.data = None

    def run(self):
        def onData(data):
            # TODO check on status before assigning data
            self.data = data
            #print(data)

        self.wrapper = ClientWrapper()
        self.client = self.wrapper.Client()
        universe = 1
        self.client.RegisterUniverse(universe, self.client.REGISTER, onData)
        print('running thread')
        self.wrapper.Run()

    def exit(self):
        try:
            self.wrapper.Terminate()
        except:
            self.wrapper.Stop()

    def getData(self):
        # return or print?
        print(self.data)
Exemple #3
0
class DMXAdapter(LightAdapter):
    def __init__(self):
        pass

    def start(self):
        from ola.ClientWrapper import ClientWrapper
        from ola.DMXConstants import DMX_MIN_SLOT_VALUE, DMX_MAX_SLOT_VALUE, DMX_UNIVERSE_SIZE
        self._universe = 0
        self._wrapper = ClientWrapper()
        self._client = self._wrapper.Client()

        self.run()

    # TODO We could use OLA's internal event scheduling system, but currently
    # I'm not aware of any obvious reason to do so. Nevertheless it bears
    # further investigation.

    def _sent_callback(self, status):
        if (not status.Succeeded()):
            # TODO catch this and report it in our heartbeat
            log.error("Failed to send DMX: %s" % status.message)
        # Always stop, as we call ourselves from a loop
        self._wrapper.Stop()

    def send(self, data):
        self._client.SendDmx(0, data, self._sent_callback)
        self._wrapper.Run()

    def run(self):
        dt_start = time.time_ns()

        # awkwardly wait around while we waight for an animator to be assigned
        while not self.animator:
            time.sleep(1)

        while True:
            dt = time.time_ns() - dt_start
            dt_start = time.time_ns()

            self.animator.step(dt / (10**9))

            with self.animator.lock:
                self.send(self.animator.lightstate)

            # TODO use configuration
            time.sleep(1 / 60)
Exemple #4
0
class DMX(Thread):
    def __init__(self, lights, effects):
        super().__init__()
        self.lights = lights
        self.running = False
        self.array = array.array('B', [0] * 512)
        self.effects = effects
        self.bpm = 30

    def run(self):
        self.wrapper = ClientWrapper()
        self.running = True
        while self.running:
            self.computeEffects()
            self.computeDMX()
            self.sendDMX()
            time.sleep(50e-3)
            # time.sleep(1)

    def stop(self):
        self.running = False

    def computeEffects(self):
        t = time.perf_counter()
        effect_duration = 60 / self.bpm
        t0_1 = (t % effect_duration) / effect_duration
        for effect in self.effects:
            effect(t0_1)

    def computeDMX(self):
        self.array = array.array('B', [0] * 512)
        for l in self.lights:
            l.writeDMX(self.array)

    def sendDMX(self):
        client = self.wrapper.Client()
        universe = 0
        client.SendDmx(universe, self.array, lambda x: self.wrapper.Stop())
        self.wrapper.Run()
Exemple #5
0
class Artnet(Thread):
    def __init__(self, settings):
        self._w = 0
        self._h = 0
        self._mapping = None
        self._settings = settings
        self._serial_device = self._settings.SERIAL_DEVICE

        self._load_config()

        self.wrapper = None
        self.universe = 1

        super(Artnet, self).__init__()

    def _load_config(self):
        configfile = open(self._settings.WALL_CONFIG_FILE, 'r')
        data = simplejson.load(configfile)
        configfile.close()
        self._w = int(data['w'])
        self._h = int(data['h'])
        self._mapping = {}
        for k, v in data['mapping'].items():
            self._mapping[int(k)] = int(v)

    def _dmxdata(self, data):
        pindex = 0

        fdata = []

        for y in range(self._h):
            for x in range(self._w):
                r = data[pindex * 3]
                g = data[pindex * 3 + 1]
                b = data[pindex * 3 + 2]
                color = correct_rgb((r, g, b))
                fdata.extend([0xFF, self._mapping[y * self._w + x]])
                fdata.extend(color)
                pindex += 1

        self._serial_device.write("".join([chr(v) for v in fdata]))

    def run(self):
        if self.wrapper:
            self.wrapper.Stop()

        try:
            self.wrapper = ClientWrapper()
        except OLADNotRunningException:
            print "Start olad first"
            sys.exit(1)

        client = self.wrapper.Client()
        client.RegisterUniverse(self.universe, client.REGISTER, self._dmxdata)

        self._load_config()
        self.wrapper.Run()

    def play(self):
        self.start()

    def stop(self):
        self.wrapper.Stop()
class OLAThread(threading.Thread):
    """connect to olad in a threaded way."""
    def __init__(self):
        """create new OLAThread instance."""
        # super().__init__()
        # super(threading.Thread, self).__init__()
        threading.Thread.__init__(self)

        self.wrapper = None
        self.client = None

        self.state = OLAThread_States.standby

        self.flag_connected = False
        self.flag_wait_for_ola = False

        # self.start()

    def run(self):
        """run state engine in threading."""
        print("run")
        print("self.state: {}".format(self.state))
        while self.state is not OLAThread_States.standby:
            if self.state is OLAThread_States.waiting:
                # print("state - waiting")
                self.ola_waiting_for_connection()
            elif self.state is OLAThread_States.connected:
                self.ola_connected()
            elif self.state is OLAThread_States.running:
                self.ola_wrapper_run()
            # elif self.state is OLAThread_States.stopping:
            #     pass
            # elif self.state is OLAThread_States.starting:
            #     pass

    def ola_wrapper_run(self):
        """run ola wrapper."""
        print("run ola wrapper.")
        try:
            self.wrapper.Run()
        except KeyboardInterrupt:
            self.wrapper.Stop()
            print("\nstopped")
        except socket.error as error:
            print("connection to OLAD lost:")
            print("   error: " + error.__str__())
            self.flag_connected = False
            self.state = OLAThread_States.waiting
            # except Exception as error:
            #     print(error)

    def ola_waiting_for_connection(self):
        """connect to ola."""
        print("waiting for olad....")
        self.flag_connected = False
        self.flag_wait_for_ola = True
        while (not self.flag_connected) & self.flag_wait_for_ola:
            try:
                # print("get wrapper")
                self.wrapper = ClientWrapper()
            except OLADNotRunningException:
                time.sleep(0.5)
            else:
                self.flag_connected = True
                self.state = OLAThread_States.connected

        if self.flag_connected:
            self.flag_wait_for_ola = False
            print("get client")
            self.client = self.wrapper.Client()
        else:
            print("\nstopped waiting for olad.")

    def ola_connected(self):
        """
        just switch to running mode.

           this can be overriden in a subclass.
        """
        self.state = OLAThread_States.running

    # dmx frame sending
    def dmx_send_frame(self, universe, data):
        """send data as one dmx frame."""
        if self.flag_connected:
            try:
                # temp_array = array.array('B')
                # for channel_index in range(0, self.channel_count):
                #     temp_array.append(self.channels[channel_index])

                # print("temp_array:{}".format(temp_array))
                # print("send frame..")
                self.wrapper.Client().SendDmx(
                    universe,
                    data,
                    # temp_array,
                    self.dmx_send_callback)
                # print("done.")
            except OLADNotRunningException:
                self.wrapper.Stop()
                print("olad not running anymore.")
        else:
            # throw error
            pass

    def dmx_send_callback(self, state):
        """react on ola state."""
        if not state.Succeeded():
            self.wrapper.Stop()
            self.state = OLAThread_States.waiting
            print("warning: dmxSent does not Succeeded.")
        else:
            # print("send frame succeeded.")
            pass

    # managment functions
    def start_ola(self):
        """switch to state running."""
        print("start_ola")
        if self.state == OLAThread_States.standby:
            self.state = OLAThread_States.waiting
            self.start()

    def stop_ola(self):
        """stop ola wrapper."""
        if self.flag_wait_for_ola:
            print("stop search for ola wrapper.")
            self.flag_wait_for_ola = False
        if self.flag_connected:
            print("stop ola wrapper.")
            self.wrapper.Stop()
        # stop thread
        self.state = OLAThread_States.standby
        # wait for thread to finish.
        self.join()
Exemple #7
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
Exemple #8
0
    reader = conn.makefile('r')

    print "Client recieved, starting loop"

    try:
        while process_line(reader.readline()):
            pass
    finally:
        print "Exiting server"
        s.close()
        reader.close()


print("Bringing up house")
empty = array('B', [DMX_MIN_SLOT_VALUE] * DMX_UNIVERSE_SIZE)
empty[106] = DMX_MAX_SLOT_VALUE
empty[107] = DMX_MAX_SLOT_VALUE
client.SendDmx(UNIVERSE, empty)

print("Can you see the house?")
if not raw_input("y/n").startswith('y'):
    print("Aborting")
    exit(0)

try:
    start_server()
finally:
    empty = array('B', [DMX_MIN_SLOT_VALUE] * DMX_UNIVERSE_SIZE)
    client.SendDmx(UNIVERSE, empty)
    client_wrapper.Stop()
Exemple #9
0
class OLA(QThread):
    """
    Separate Thread that launch OLA server and run OLA Client
    It runs only if OLA server is responding
    """
    # signal that there is a new frame for the selected universe
    universeChanged = pyqtSignal()
    # signal that there is a new universes_list to display
    universesList = pyqtSignal()
    # signal that there is a new list of devices to display
    devicesList = pyqtSignal()
    # signal that there is a new list of inputs portsto display
    inPortsList = pyqtSignal()
    # signal that there is a new list of inputs portsto display
    outPortsList = pyqtSignal()
    def __init__(self):
        QThread.__init__(self)
        self.server = None
        self.client = None
        try:
            # launch OLA server
            self.server = OlaServer()
        except:
            # OLA server does not work properly
            print('OLA server not responding')
        sleep(0.1)
        # start the thread
        if self.server:
            self.start()
        else:
            print('no server is running, cannot start a client')

    def __del__(self):
        self.wait()

    def run(self):
        """
        the running thread
        """
        try:
            self.wrapper = ClientWrapper()
            self.client = self.wrapper.Client()
            if debug:
                print('connected to OLA server')
            self.wrapper.Run()
        except OLADNotRunningException:
            if debug:
                print('cannot connect to OLA')

    def stop(self):
        """
        stop the OLA client wrapper
        """
        if self.client:
            self.wrapper.Stop()
            if debug:
                print('OLA client is stopped')
        if self.server:
            self.server.stop()
            if debug:
                print('OLA server is stopped')
        return True
class pixel_multiplier(object):
    class universe_listener(object):
        class universe_sender(object):
            def __init__(self, universe, pixel_groups):
                self.universe = universe
                self.pixel_groups = [
                    group for group in pixel_groups
                    if group.destination_universe == universe
                ]
                self.pixel_groups.sort()

            def __lt__(self, other):
                return self.universe < other.universe

            def generate_frame(self, received_frame):
                new_frame = array.array('B')
                for group in self.pixel_groups:
                    new_frame.extend(
                        (group.destination_offset - len(new_frame)) * [0])
                    pixel = received_frame[group.
                                           source_offset:group.source_offset +
                                           3]
                    new_frame.extend(pixel * group.number_of_pixels)
                return new_frame

        def __init__(self, universe, pixel_groups, ola_client):
            self.universe = universe
            self.ola_client = ola_client
            self.pixel_groups = [
                group for group in pixel_groups
                if group.source_universe == universe
            ]
            self.destination_universes = {
                group.destination_universe
                for group in self.pixel_groups
            }
            self.senders = [
                self.universe_sender(u, self.pixel_groups)
                for u in self.destination_universes
            ]
            self.senders.sort()
            ola_client.RegisterUniverse(universe, ola_client.REGISTER,
                                        self.frame_received)

            def __lt__(self, other):
                return self.universe < other.universe

        def frame_received(self, received_frame):
            def frame_sent(state):
                pass

            for sender in self.senders:
                new_frame = sender.generate_frame(received_frame)
                self.ola_client.SendDmx(sender.universe, new_frame, frame_sent)

    class pixel_group(object):
        def __init__(self, source_universe, source_channel,
                     destination_universe, destination_channel,
                     number_of_pixels):
            self.source_universe = source_universe
            self.source_offset = source_channel - 1
            self.destination_universe = destination_universe
            self.destination_offset = destination_channel - 1
            self.number_of_pixels = number_of_pixels

        def __lt__(self, other):
            return self.destination_offset < other.destination_offset

    def __init__(self, groups):
        self.pixel_groups = [
            self.pixel_group(group[0], group[1], group[2], group[3], group[4])
            for group in groups
        ]
        self.source_universes = {
            group.source_universe
            for group in self.pixel_groups
        }
        self.ola_client_wrapper = ClientWrapper()
        self.ola_client = self.ola_client_wrapper.Client()
        self.listeners = [
            self.universe_listener(u, self.pixel_groups, self.ola_client)
            for u in self.source_universes
        ]
        self.listeners.sort()

    def run(self):
        self.ola_client_wrapper.Run()

    def stop(self):
        self.ola_client_wrapper.Stop()
class InteractiveModeController(cmd.Cmd):
    """Interactive mode!"""
    def __init__(self, universe, uid, sub_device, pid_file):
        """Create a new InteractiveModeController.

    Args:
      universe:
      uid:
      sub_device:
      pid_file:
    """
        cmd.Cmd.__init__(self)
        self._universe = universe
        self._uid = uid
        self._sub_device = sub_device

        self.pid_store = PidStore.GetStore(pid_file)
        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 intrepreter."""
        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, l):
        """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, l):
        """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, l):
        """Run full RDM discovery for this universe."""
        self.client.RunRDMDiscovery(self._universe, True, self._DiscoveryDone)
        self.wrapper.Run()

    def do_incremental_discovery(self, l):
        """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 = [
            pid.name.lower() for pid in pids
            if pid.RequestSupported(request_type)
        ]

        pid_names.sort()
        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

        rdm_args = args[1:]
        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, 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
Exemple #12
0
    else:
        print("get client")
        client = wrapper.Client()

        if universe == -1:
            print("request universes")
            print(client.FetchUniverses(get_unused_universes))
            wrapper.Run()
            print("wait for universes...")
            try:
                while not global_flag_got_universes:
                    time.sleep(0.1)
                    print(".. ({})".format(global_flag_got_universes))
            except KeyboardInterrupt:
                print("\nstopped waiting for universes.")

        print("add event to a SendDMXFrame")
        wrapper.AddEvent(TICK_INTERVAL, SendDMXFrame)

        print("run")
        try:
            wrapper.Run()
        except KeyboardInterrupt:
            wrapper.Stop()
            print("\nstopped")
        except socket.error as error:
            print("connection to OLAD lost:")
            print("   error: " + error.__str__())
        # except Exception as error:
        #     print(error)
Exemple #13
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"])))
class DMX_Pixel_LED (Lighting_Controller):


    def __init__(self):
        Lighting_Controller.__init__(self)

        # dmx bits
        self.wrapper = ClientWrapper()
        self.client = self.wrapper.Client()
        self.universe = 0 # type: int
        self.wait_on_dmx = threading.Event()
        self.dmx_succeeded = False

    def update(self, leds):
        """
        Send leds array to DMX controller
        :return: True if dmx update was successful
        """
        if self.origin != Lighting_Controller.NORTH:
            leds = self.flip_leds(leds, 4)
        self.client.SendDmx(self.universe, leds, self.dmx_callback)
        self.wait_on_dmx.clear()
        self.dmx_succeeded = False
        self.wrapper.Run()
        self.wait_on_dmx.wait()
        return self.dmx_succeeded

    def update_sequence(self, sequence, delays, repetitions):
        self.dmx_succeeded = True
        idx = 0
        num_delays = len(delays)
        for _ in range(repetitions):
            for leds in sequence:
                if self.origin != Lighting_Controller.NORTH:
                    leds = self.flip_leds(leds, 4)
                self.client.SendDmx(self.universe, leds, self.dmx_callback)
                sleep(delays[idx])
                if not self.dmx_succeeded:
                    break
                idx = (idx + 1) % num_delays
        return self.dmx_succeeded

    def set_origin(self, pole):
        """
        Sets origin of lights to either begin on NORTH or SOUTH pole. This will reverse the leds list when running
        from SOUTH.
        :param pole: Lighting_Controller.NORTH or Lighting_Controller.SOUTH
        :return: NONE
        """
        if pole != self.origin and pole in [Lighting_Controller.NORTH, Lighting_Controller.SOUTH]:
            self.origin = pole

    def flip_leds(self, leds, bytes_per_led):
        """
        Reverses the led byte array
        :param leds:
        :return:
        """
        num_bytes = len(leds)
        byte_array = array.array('B', [0 for i in range(num_bytes)])
        jdx = 0
        for idx in range(num_bytes - bytes_per_led, 0, -bytes_per_led):
            byte_array[jdx] = leds[idx]
            byte_array[jdx+1] = leds[idx+1]
            byte_array[jdx+2] = leds[idx+2]
            byte_array[jdx+3] = leds[idx+3]
            jdx += 4
        return byte_array

    def fade(self, location, color, milliseconds):
        """
        Transitions light to new color over time period in milliseconds
        :param location: index in self.devices to effect
        :param color:
        :param milliseconds: transition time to new color
        :return: None
        """
        pass

    def dmx_callback(self, status):
        """
        :param status: status code returned by SendDmx()
        :return: None
        """
        self.dmx_succeeded = status.Succeeded()
        self.wrapper.Stop()
        self.wait_on_dmx.set()
Exemple #15
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)))
Exemple #16
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)