def main(): # Alternate ways of declaring strip: # Only use hardware SPI # print "Data pin GPIO/BCM {0}".format(datapin) # print "Clock pin GPIO/BCM {0}".format(clockpin) print("Opening LED strip with {0} pixels".format(numpixels)) # NOTE: This is not the same as omitting data/clock pin args!!! # strip = Adafruit_DotStar(numpixels, datapin, clockpin, order='gbr') # Use SPI (pins 10=MOSI, 11=SCLK) # strip = Adafruit_DotStar(numpixels, datapin, clockpin, order='grb') # Use SPI (pins 10=MOSI, 11=SCLK) # strip = Adafruit_DotStar(numpixels) # Use SPI (pins 10=MOSI, 11=SCLK) # strip = Adafruit_DotStar(numpixels, order='gbr') # Use SPI (pins 10=MOSI, 11=SCLK) # NOTE: The default color order is BRG (not RGB) strip = Adafruit_DotStar( numpixels, order='rgb'.encode('utf-8')) # Use SPI (pins 10=MOSI, 11=SCLK) strip.begin() # Initialize pins for output strip.setBrightness(brightness) # Limit brightness #strip.setBrightness(127) # Unlimited brightness print("Hit Ctrl-C to end test") try: while True: # scroll_pixels(strip, Color(255, 83, 13), numpixels * 20) # This one pretty much produces the expected results (gamma applied) #scroll_pixels(strip, Color(255, 83, 13, gamma=True), numpixels * 20) #scroll_pixels(strip, rgb_color(255, 0, 0), numpixels * 20) #scroll_pixels(strip, rgb_color(0, 255, 0), numpixels * 20) #scroll_pixels(strip, rgb_color(0, 0, 255), numpixels * 20) #solid_fill(strip, Color(255, 0, 0, gamma=True), iterations=2) #solid_fill(strip, Color(0, 255, 0, gamma=True), iterations=2) #solid_fill(strip, Color(0, 0, 255, gamma=True), iterations=2) wheel_fill(strip, iterations=1) print("Pass complete") except (KeyboardInterrupt, Exception) as ex: print(ex) print("") print("Turning off all lights...") # Not well documented, but this is how you turn # off everything strip.clear() strip.show() strip.close() print("Strip closed")
def main(): # Alternate ways of declaring strip: print("Data pin GPIO/BCM {0}".format(datapin)) print("Clock pin GPIO/BCM {0}".format(clockpin)) print("Opening LED strip with {0} pixels".format(numpixels)) # The default here is SPI at 800 KHz # strip = Adafruit_DotStar(numpixels) # Use SPI (pins 10=MOSI, 11=SCLK by default) # This strip uses the specified pins at 800 KHz #strip = Adafruit_DotStar(numpixels, datapin, clockpin, order='gbr') # Use SPI (pins 10=MOSI, 11=SCLK) strip = Adafruit_DotStar( numpixels, order='gbr'.encode('utf-8')) # Use SPI (pins 10=MOSI, 11=SCLK) # strip = Adafruit_DotStar(numpixels, 32000000) # SPI @ ~32 MHz # strip = Adafruit_DotStar() # SPI, No pixel buffer # strip = Adafruit_DotStar(32000000) # 32 MHz SPI, no pixel buf # See image-pov.py for explanation of no-pixel-buffer use. # Append "order='gbr'" to declaration for proper colors w/older DotStar strips) strip.begin() # Initialize pins for output # strip.setBrightness(64) # Limit brightness to ~1/4 duty cycle strip.setBrightness(brightness) # Limit brightness # Runs 10 LEDs at a time along strip, cycling through red, green and blue. # This requires about 200 mA for all the 'on' pixels + 1 mA per 'off' pixel. print("Hit Ctrl-C to end test") try: while True: random_pixels(strip) run_all_effects(strip) scroll_pixels(strip, numpixels * 20) except (KeyboardInterrupt, Exception) as ex: print(ex) print("") print("Turning off all lights...") # Not well documented, but this is how you turn # off everything strip.clear() strip.show() strip.close() print("Strip closed")
class PovFan: def __init__(self): datapin = 10 clockpin = 11 self.column = None self.width = 0 self.sequence = [] self.cur_column = 0 self.images_folder = "" self.next_buffer_index = 0 self.last_push = 0 self.image_start_time = 0 if is_running_on_pi: self.strip = Adafruit_DotStar(0, datapin, clockpin, 18500000) else: self.strip = None def add_image(self, image_path, reverse): if is_running_on_pi == False: # print "add_image" return img = Image.open(image_path).convert("RGB") pixels = img.load() width = img.size[0] height = img.size[1] if (height < STRIP_LENGTH): assert ("trying to load image too small") column = [0 for x in range(width)] for x in range(width): column[x] = bytearray(STRIP_LENGTH * 4) bytess = img.tobytes() for x in range(width): offset = x * 3 multiplier = width * 3 self.strip.prepareBuffer(column[x], bytess, offset, multiplier, reverse) self.sequence.append(column) self.width = width img.close() def disabled_animation(): pass def clear_fan(): pass def loading_animation(): pass #TODO: set sequence length def load_sequence(self, sequence_path, fan_id, seq_size=-1): if is_running_on_pi == False: # print "load_sequence: ", sequence_path, fan_id return start = time.time() path = os.path.join(self.images_folder, 'incoming_images', sequence_path, "fan_" + str(fan_id)) files = sorted(glob.glob(os.path.join(path, "*.png"))) for i in range(len(files)): print "loading image ", i self.add_image(files[i], i % 2) print "loading took ", time.time() - start def transition_image(self, next_image): for i in range(len(self.column)): self.strip.pushBuffer(self.column[i], next_image[i], self.next_buffer_index) self.next_buffer_index = self.next_buffer_index + 1 if self.next_buffer_index / 2 > len(next_image[i]): self.next_buffer_index = 0 print "restart buffer loop" def next_image(self, magnet_synced=False): # check if image have been looping for enough time if time.time() - self.image_start_time > 15: self.next_buffer_index = 0 self.image_start_time = time.time() self.cur_column = (self.cur_column + 1) % len(self.sequence) print "next image is ", self.cur_column self.transition_image(self.sequence[self.cur_column]) def no_magnet_callback(self, timing): timing["lapse_time"] = timing["no_magnet_lapse_time"] timing["last_update"] = time.time() timing["lapses"] = timing["lapses"] + 1 timing["need_swap"] = 0 if timing["lapses"] % 10 == 0: print "MAGNET SENSOR INACTIVE! FALLBACK ESTIMATING SPEED" print "lapse ", timing["lapses"], " refresh count: ", timing[ "refresh_count"] print "lapse time", timing["lapse_time"] timing["refresh_count"] = 0 def play(self, length): if len(self.sequence) == 0: print "No sequence loaded! Cancel play" return if is_running_on_pi == False: return self.strip.begin() end_time = length + time.time() PIXELS_IN_CIRCLE = 2 * self.width self.column = [] for i in range(len(self.sequence[self.cur_column])): r = bytearray(STRIP_LENGTH * 4) r[:] = self.sequence[0][i] self.column.append(r) self.cur_column = 0 self.image_start_time = time.time() timing = { "lapse_time": 0.18, # time to complete lapse "last_update": time.time(), # last frame time "lapses": 0, # number of whole rotations (or every magnet on) "refresh_count": 0, # number of columns showed "need_swap": 0, # track for estimating mid-lapse image swap "max_lapse_time": 0.33, # max time allowed before force swap "use_magnet": True, "no_magnet_lapse_time": 0.2 } print "playing sequence for ", length, "seconds" if is_running_on_pi: def sync_magnet(counter): a = timing def magnet_cbk(m): if not timing["use_magnet"]: return timing["lapse_time"] = m.estimated_rpm() timing["last_update"] = time.time() timing["lapses"] = timing["lapses"] + 1 timing["need_swap"] = 0 if timing["lapses"] % 10 == 0: # print "lapse ", timing["lapses"], " refresh count: ", timing["refresh_count"] # print "lapse time", timing["lapse_time"] timing["refresh_count"] = 0 return magnet_cbk magnet = MagnetButton(16) magnet.when_magnet = sync_magnet(timing) magnet.set_timeout(timing["max_lapse_time"]) while end_time > timing["last_update"]: timing["use_magnet"] = not (magnet.is_not_responding()) if not timing["use_magnet"]: if time.time( ) > timing["last_update"] + timing["no_magnet_lapse_time"]: self.no_magnet_callback(timing) if timing["need_swap"] == 0: self.next_image() timing["need_swap"] = 1 c = int(PIXELS_IN_CIRCLE * (time.time() - timing["last_update"]) / timing["lapse_time"]) # TODO: make this cleaner... if c >= (self.width): if timing["need_swap"] == 1: self.next_image() timing["need_swap"] = 2 ## if overflowing since lapse is longer now c = c % self.width self.strip.show(self.column[c]) timing["refresh_count"] = timing["refresh_count"] + 1 time.sleep(0.0001) magnet.close() else: while end_time > timing["last_update"]: timing["last_update"] = time.time() self.strip.clear() self.strip.close() def stop(self): self.strip.clear() self.strip.close()
class UtilityFan: def __init__(self): datapin = 10 clockpin = 11 self.buffer = bytearray(STRIP_LENGTH * 4) self.buffer_clear = bytearray(STRIP_LENGTH * 4) self.color_hsv = [0, 1, 0.7] self.start_time = time.time() self.cur_trail = 0 for i in range(0, len(self.buffer_clear), 4): self.buffer_clear[i] = 0xFF self.buffer_clear[i + rOffset] = 0 self.buffer_clear[i + gOffset] = 0 self.buffer_clear[i + bOffset] = 0 if is_running_on_pi: self.strip = Adafruit_DotStar(0, datapin, clockpin, 18500000) else: self.strip = None def animation_step(self): if is_running_on_pi == False: return self.color_hsv[0] += 0.002 color = colorsys.hsv_to_rgb(self.color_hsv[0], self.color_hsv[1], self.color_hsv[2]) t = time.time() - self.start_time for i in range(0, len(self.buffer), 4): pos = abs(STRIP_LENGTH / 2 - i / 4) # v = 0.1* (0.5+ 0.3*math.sin(t*3)) * ((1 + math.sin(i*0.1 + t*11)) + (1 + math.sin(i*0.2 - t*7)) ) v = abs(self.cur_trail - pos) / 144.0 self.buffer[i] = 0xFF self.buffer[i + rOffset] = gamma[int(v * 255 * color[0])] #int(color[0] * v) self.buffer[i + gOffset] = gamma[int( v * 255 * color[1])] #gamma[int(color[1] * v) self.buffer[i + bOffset] = gamma[int(v * 255 * color[2])] #int(color[2] * v) self.cur_trail = abs(self.cur_trail + 1) % (STRIP_LENGTH) self.strip.show(self.buffer) def next(self, length): end_time = length + time.time() last_update = time.time() last_frame = time.time() self.strip.begin() while end_time > last_update: last_update = time.time() if last_frame + 0.2 < last_update: last_frame = last_update self.animation_step() self.strip.close() def clear(self): self.strip.begin() self.strip.show(self.buffer_clear) self.strip.close()
class PovFan: def __init__(self): datapin = 10 clockpin = 11 self.column = None self.width = 0 self.sequence = [] self.cur_column = 0 self.images_folder = "" if is_running_on_pi: self.strip = Adafruit_DotStar(0, datapin, clockpin, 18500000) else: self.strip = None def add_image(self, image1_path, image2_path): if not is_running_on_pi: # print "add_image" return img1 = Image.open(image1_path).convert("RGB") pixels1 = img1.load() width = img1.size[0] height = img1.size[1] img2 = Image.open(image2_path).convert("RGB") pixels2 = img2.load() if (height < STRIP_LENGTH): assert("trying to load image too small") column = [0 for x in range(width*2)] for x in range(width*2): column[x] = bytearray(STRIP_LENGTH * 4) bytess = img1.tobytes() for x in range(width): offset = x * 3 multiplier = width * 3 self.strip.prepareBuffer(column[x], bytess, offset, multiplier, False) bytess = img2.tobytes() for x in range(width): offset = x * 3 multiplier = width * 3 self.strip.prepareBuffer(column[x+width], bytess, offset, multiplier, True) column.reverse() self.sequence.append(column) self.width = width*2 img1.close() img2.close() def disabled_animation(): pass def clear_fan(): pass def loading_animation(): pass #TODO: set sequence length def load_sequence(self, sequence_path, fan_id, seq_size = -1): if is_running_on_pi == False: # print "load_sequence: ", sequence_path, fan_id return start = time.time() path = os.path.join(self.images_folder, 'incoming_images', sequence_path, "fan_"+str(fan_id)) files = sorted( glob.glob( os.path.join(path, "*.png") )) for i in range(len(files)): print "load images ", i, i+1 if i%2 == 0 and i+1 < len(files): self.add_image(files[i], files[i+1]) print "loading took ", time.time() - start def next_image(self, magnet_synced=False): self.cur_column = (self.cur_column + 1) % len(self.sequence) # Make sure that is on even numbered image when hitting magnet if magnet_synced and self.cur_column % 2 == 1: self.cur_column = (self.cur_column + 1) % len(self.sequence) self.column = self.sequence[self.cur_column] # print "showing frame #",self.cur_column def no_magnet_callback(self, timing): timing["lapse_time"] = timing["no_magnet_lapse_time"] timing["last_update"] = time.time() timing["lapses"] = timing["lapses"] + 1 timing["need_swap"] = 0 if timing["lapses"] % 10 == 0: print "MAGNET SENSOR INACTIVE! FALLBACK ESTIMATING SPEED" print "lapse ", timing["lapses"], " refresh count: ", timing["refresh_count"] print "lapse time", timing["lapse_time"] timing["refresh_count"] = 0 def play(self, length): if len(self.sequence) == 0: print "No sequence loaded! Cancel play" return if is_running_on_pi == False: return self.strip.begin() end_time = length + time.time() PIXELS_IN_CIRCLE = self.width angle_offset_pixels = (int) (PHYSICAL_ANGLE_OFFSET * 360.0 / PIXELS_IN_CIRCLE) print "offsting image by " + str(angle_offset_pixels) self.column = self.sequence[self.cur_column] timing = { "lapse_time": 0.18, # time to complete lapse "last_update": time.time(), # last frame time "lapses": 0, # number of whole rotations (or every magnet on) "refresh_count": 0, # number of columns showed "need_swap": 0, # track for estimating mid-lapse image swap "max_lapse_time": 0.33, # max time allowed before force swap "use_magnet": True, "no_magnet_lapse_time": 0.2 } print "playing sequence for ", length, "seconds" if is_running_on_pi: def sync_magnet(counter): a = timing def magnet_cbk(m): if not timing["use_magnet"]: return timing["lapse_time"] = m.estimated_rpm() timing["last_update"] = time.time() timing["lapses"] = timing["lapses"] + 1 timing["need_swap"] = 0 if timing["lapses"] % 10 == 0: print "lapse ", timing["lapses"], " refresh count: ", timing["refresh_count"] print "lapse time", timing["lapse_time"] timing["refresh_count"] = 0 return magnet_cbk magnet = MagnetButton(16) magnet.when_magnet = sync_magnet(timing) magnet.set_timeout(timing["max_lapse_time"]) while end_time > timing["last_update"]: timing["use_magnet"] = not (magnet.is_not_responding()) if not timing["use_magnet"]: if time.time() > timing["last_update"] + timing["no_magnet_lapse_time"]: self.no_magnet_callback(timing) if timing["need_swap"] == 0: self.next_image() timing["need_swap"] = 1 ## Angle_offset_pixels is a temp solutions .... need to fix in actual image c = angle_offset_pixels + int(PIXELS_IN_CIRCLE * (time.time() - timing["last_update"]) / timing["lapse_time"]) # TODO: make this cleaner... if c >= (self.width): # if timing["need_swap"] == 1: # self.next_image() # timing["need_swap"] = 2 ## if overflowing since lapse is longer now c = c % self.width self.strip.show(self.column[c]) timing["refresh_count"] = timing["refresh_count"] + 1 time.sleep(0.0001) magnet.close() else: while end_time > timing["last_update"]: timing["last_update"] = time.time() self.strip.show(bytearray(STRIP_LENGTH * 4)) self.strip.close() def stop(self): self.strip.clear() self.strip.close()
class PovFan: def __init__(self): datapin = 10 clockpin = 11 self.column = None self.width = 0 self.sequence = [] self.cur_column = 0 self.start_time = 0 self.fps = 16 self.images_folder = "" if is_running_on_pi: self.strip = Adafruit_DotStar(0, datapin, clockpin, 18500000) else: self.strip = None def disabled_animation(): pass def clear_fan(): pass def loading_animation(): pass #TODO: set sequence length def load_sequence(self, sequence_path, fan_id, seq_size=-1): if is_running_on_pi == False: return start = time.time() image_loader = ImageLoader() path = os.path.join(self.images_folder, 'incoming_images', sequence_path, "fan_" + str(fan_id)) files = sorted(glob.glob(os.path.join(path, "*.png"))) for i in range(len(files)): circular_image = image_loader.load_to_circular_buffer(files[i]) if (circular_image.diameter < STRIP_LENGTH): assert ( "load_sequence(): trying to load image too small for strip length" ) self.sequence.append(circular_image) print("Successfuly loaded ", len(files)) print("loading took ", time.time() - start) def get_frame(self): seq_length = len(self.sequence) elapsed_time = time.time() - self.start_time frame = int(elapsed_time * self.fps) % seq_length return self.sequence[frame] def play(self, length, display_controller): if len(self.sequence) == 0: print("No sequence loaded! Cancel play") return if is_running_on_pi == False: return if display_controller is None: display_controller = DisplayController() self.strip.begin() self.start_time = time.time() end_time = length + self.start_time black = ImageLoader.black() # angle_offset_pixels = (int) (PHYSICAL_ANGLE_OFFSET * 360.0 / PIXELS_IN_CIRCLE) # print "offsting image by " + str(angle_offset_pixels) print("playing sequence for ", length, "seconds") current_image = self.sequence[0] counter = 0 last_switch = time.time() diff = 0 if is_running_on_pi: while end_time > display_controller.last_update: diff = diff + time.time() - last_switch last_switch = time.time() current_image = self.get_frame() display_controller.update() angle = display_controller.estimate_angle() self.strip.show(current_image.get_sample_by_angle(angle)) time.sleep(0.0001) else: while end_time > timing["last_update"]: timing["last_update"] = time.time() self.stop() # self.strip.show(bytearray(STRIP_LENGTH * 4)) # self.strip.close() def stop(self): self.strip.show(ImageLoader.black()) self.strip.close()