diff --git a/limitlessled/__init__.py b/limitlessled/__init__.py index 38ab80f..5071bf8 100644 --- a/limitlessled/__init__.py +++ b/limitlessled/__init__.py @@ -11,7 +11,7 @@ # Various constants. MIN_WAIT = 0.1 -REPS = 3 +DEFAULT_REPS = 3 MAX_GROUPS = 4 diff --git a/limitlessled/bridge.py b/limitlessled/bridge.py index e7e7262..36d9129 100644 --- a/limitlessled/bridge.py +++ b/limitlessled/bridge.py @@ -5,7 +5,7 @@ import time import threading -from limitlessled import MIN_WAIT, REPS +from limitlessled import MIN_WAIT, DEFAULT_REPS from limitlessled.group.rgbw import RgbwGroup, RGBW from limitlessled.group.white import WhiteGroup, WHITE @@ -15,6 +15,7 @@ BRIDGE_SHORT_VERSION_MIN = 3 BRIDGE_LONG_BYTE = 0x55 SELECT_WAIT = 0.025 +DEFAULT_PRIORITY = 10 def group_factory(bridge, number, name, led_type): @@ -37,7 +38,8 @@ def group_factory(bridge, number, name, led_type): class Bridge(object): """ Represents a LimitlessLED bridge. """ - def __init__(self, ip, port=BRIDGE_PORT, version=BRIDGE_VERSION): + def __init__(self, ip, port=BRIDGE_PORT, version=BRIDGE_VERSION, + reps=DEFAULT_REPS): """ Initialize bridge. Bridge version 3 through 5 (latest as of this release) @@ -50,16 +52,17 @@ def __init__(self, ip, port=BRIDGE_PORT, version=BRIDGE_VERSION): :param version: Bridge version. """ self.wait = MIN_WAIT - self.reps = REPS + self.reps = reps self.groups = [] self.ip = ip self.version = version self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._socket.connect((ip, port)) - self._command_queue = queue.Queue() + self._command_queue = queue.PriorityQueue() self._lock = threading.Lock() self.active = 0 self._selected_number = None + self._seqnum = 0 # Start queue consumer thread. consumer = threading.Thread(target=self._consume) consumer.daemon = True @@ -87,7 +90,8 @@ def add_group(self, number, name, led_type): self.groups.append(group) return group - def send(self, group, command, reps=REPS, wait=MIN_WAIT, select=False): + def send(self, group, command, reps=None, wait=MIN_WAIT, select=False, + priority=DEFAULT_PRIORITY): """ Send a command to the physical bridge. :param group: Run on this group. @@ -96,8 +100,14 @@ def send(self, group, command, reps=REPS, wait=MIN_WAIT, select=False): :param wait: Wait time in seconds. :param select: Select group if necessary. """ + if reps is None: + reps = self.reps + + seqnum = self._seqnum + self._seqnum += 1 # Enqueue the command. - self._command_queue.put((group, command, reps, wait, select)) + self._command_queue.put((priority, seqnum, group, command, reps, wait, + select)) # Wait before accepting another command. # This keeps indvidual groups relatively synchronized. sleep = reps * wait * self.active @@ -120,7 +130,8 @@ def _consume(self): """ while True: # Get command from queue. - (group, command, reps, wait, select) = self._command_queue.get() + (priority, seqnum, group, command, reps, wait, select) = \ + self._command_queue.get() # Select group if a different group is currently selected. if select and self._selected_number != group.number: self._socket.send(bytearray(group.get_select_cmd())) diff --git a/limitlessled/group/__init__.py b/limitlessled/group/__init__.py index e450944..c939c70 100644 --- a/limitlessled/group/__init__.py +++ b/limitlessled/group/__init__.py @@ -5,11 +5,11 @@ import threading import queue -from limitlessled import MIN_WAIT, REPS +from limitlessled import MIN_WAIT from limitlessled.pipeline import Pipeline, PipelineQueue -def rate(wait=MIN_WAIT, reps=REPS): +def rate(wait=MIN_WAIT, reps=None): """ Rate limit a command function. :param wait: How long to wait between commands. @@ -60,7 +60,6 @@ def __init__(self, bridge, number, name): self._thread.daemon = True self._thread.start() self.wait = MIN_WAIT - self.reps = REPS @property def on(self): @@ -91,7 +90,7 @@ def send(self, cmd, select=False): :param select: If command requires selection. """ self._bridge.send(self, cmd, wait=self.wait, - reps=self.reps, select=select) + reps=self.bridge.reps, select=select) def enqueue(self, pipeline): """ Start a pipeline. @@ -114,7 +113,7 @@ def _wait(self, duration, commands): :returns: Wait in seconds. """ wait = (duration / commands) - \ - (self.wait * self.reps * self._bridge.active) + (self.wait * self.bridge.reps * self._bridge.active) if wait < 0: wait = 0 return wait @@ -128,7 +127,7 @@ def _scaled_steps(self, duration, steps, total): :returns: Steps scaled to time and total. """ return math.ceil(duration / - (self.wait * self.reps * self._bridge.active) * + (self.wait * self.bridge.reps * self._bridge.active) * (steps / total)) def __str__(self):