class MultiplexThread(object): stopped = None def __init__(self, displays_manager): self._display_thread = GPIOThread( target=self._start, args=() ) self.stopped = False self.manager = displays_manager self.sleep = 0.005 def start(self): self._display_thread.start() def _start(self): while not self.stopped: self.rewrite(self.manager.displays) def rewrite(self, displays): for display in displays: display._rewrite() display.on() sleep(self.sleep) display.off() def stop(self): self.stopped = True self._display_thread.stop()
def blink(self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0, n=None, background=True, fps=25, min_value=0, max_value=1): if not 0 <= min_value <= 1: raise OutputDeviceBadValue("min_value must be between 0 and 1") if not 0 <= max_value <= 1: raise OutputDeviceBadValue("max_value must be between 0 and 1") if not min_value <= max_value: raise OutputDeviceBadValue("min_value must be less than max_value") try: self._stop_blink() except RuntimeError as e: if "cannot join thread before it is started" not in str(e): raise e self._blink_thread = GPIOThread(target=self._blink_device, args=(on_time, off_time, fade_in_time, fade_out_time, n, fps, min_value, max_value)) self._blink_thread.start() if not background: self._blink_thread.join() self._blink_thread = None
def try_start_polling(self): if (not self._poll_thread and self._getter and self._callback and self._detector): self._poll_thread = GPIOThread( target=self._poll, args=(self._poll_interval, self._debounce_time, self._getter, self._detector, self._callback)) self._poll_thread.start()
def __init__(self, displays_manager): self._display_thread = GPIOThread( target=self._start, args=() ) self.stopped = False self.manager = displays_manager self.sleep = 0.005
def ease(self, easing_function, duration=None): self._stop_blink() self._blink_thread = GPIOThread( target=self._ease, args=( easing_function, duration, ) ) self._blink_thread.start()
class MyPWMLED(PWMLED): def ease(self, easing_function, duration=None): self._stop_blink() self._blink_thread = GPIOThread( target=self._ease, args=( easing_function, duration, ) ) self._blink_thread.start() def _ease(self, easing_function, duration): start = now = time.time() if duration: end = now + duration while not duration or now < end: v = easing_function(now - start) self._write(v) if self._blink_thread.stopping.wait(0.01): break now = time.time()
class DebouncingPoller: """Manages debouncing and polling a function periodically in the background. Calls a given getter periodically and when the debounced value changes such that detector(old, new) returns true, the callback is called. Only runs while detector, getter, and callback are set. """ _MIN_POLL_INTERVAL = .0001 def __init__(self, value_getter, callback, detector=lambda old, new: True): self._poll_thread = None self._debounce_time = .001 self._poll_interval = .00051 self._getter = value_getter self._detector = detector self._callback = callback @property def poll_interval(self): return self._poll_interval @poll_interval.setter def poll_interval(self, interval): self._poll_interval = max(interval, self._MIN_POLL_INTERVAL) self.restart_polling() @property def debounce_time(self): return self._debounce_time @debounce_time.setter def debounce_time(self, debounce_time): self._debounce_time = debounce_time self.restart_polling() @property def callback(self): return self._callback @callback.setter def callback(self, callback): self.stop_polling() self._callback = callback self.try_start_polling() @property def detector(self): return self._detector @detector.setter def detector(self, detector): self._detector = detector self.restart_polling() def try_start_polling(self): if (not self._poll_thread and self._getter and self._callback and self._detector): self._poll_thread = GPIOThread( target=self._poll, args=(self._poll_interval, self._debounce_time, self._getter, self._detector, self._callback)) self._poll_thread.start() def stop_polling(self): if self._poll_thread: self._poll_thread.stop() self._poll_thread = None def restart_polling(self): self.stop_polling() self.try_start_polling() # Only called from the polling thread. def _poll(self, poll_interval, debounce_interval, getter, detector, callback): """Debounces and monitors the value retrieved by _getter. Triggers callback if detector(old_value, new_value) returns true. Args: poll_interval: positive float, time in seconds between polling the getter. debounce_interval: positive float, time in seconds to wait after a change to allow a future change to the value to trigger the callback. getter: function() -> value, gets the value. This will be called periodically and the value type will be the same type passed to the detector function. detector: function(old, new) -> bool, filters changes to determine when the callback should be called. Can be used for edge detection callback: function() to be invoked when detector conditions are met. """ last_time = time.time() last_value = getter() while not self._poll_thread.stopping.wait(poll_interval): value = getter() new_time = time.time() if not debounce_interval or (new_time - last_time) > debounce_interval: if detector(last_value, value): callback() last_value = value last_time = new_time
class PWMTransitionOutputDevice(PWMOutputDevice): def _blink_device(self, on_time, off_time, fade_in_time, fade_out_time, n, fps=25, min_value=0, max_value=1): if not 0 <= min_value <= 1: raise OutputDeviceBadValue("min_value must be between 0 and 1") if not 0 <= max_value <= 1: raise OutputDeviceBadValue("max_value must be between 0 and 1") if not min_value <= max_value: raise OutputDeviceBadValue("min_value must be less than max_value") amount_to_move = max_value - min_value sequence = [] if fade_in_time > 0: sequence += [ (min_value + (i * (amount_to_move / fps) / fade_in_time), 1 / fps) for i in range(int(fps * fade_in_time)) ] if on_time is not None: sequence.append((max_value, on_time)) if fade_out_time > 0: sequence += [ (max_value - (i * (amount_to_move / fps) / fade_out_time), 1 / fps) for i in range(int(fps * fade_out_time)) ] if off_time is not None: sequence.append((min_value, off_time)) sequence = (cycle(sequence) if n is None else chain.from_iterable( repeat(sequence, n))) for value, delay in sequence: self._write(value) if self._blink_thread.stopping.wait(delay): break def blink(self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0, n=None, background=True, fps=25, min_value=0, max_value=1): if not 0 <= min_value <= 1: raise OutputDeviceBadValue("min_value must be between 0 and 1") if not 0 <= max_value <= 1: raise OutputDeviceBadValue("max_value must be between 0 and 1") if not min_value <= max_value: raise OutputDeviceBadValue("min_value must be less than max_value") try: self._stop_blink() except RuntimeError as e: if "cannot join thread before it is started" not in str(e): raise e self._blink_thread = GPIOThread(target=self._blink_device, args=(on_time, off_time, fade_in_time, fade_out_time, n, fps, min_value, max_value)) self._blink_thread.start() if not background: self._blink_thread.join() self._blink_thread = None