def __init__(self, write_fun=None, config={}): self.config = config if write_fun is None: @coroutine def write(self, *args): print(*args) self.write = write else: self.write = write_fun self.act_led = pyb.LED(3) self.err_led = pyb.LED(1) self.pkt_led = pyb.LED(2) self.pots = [0] * 4 self.percolator = \ Percolator(WS2812(spi_bus=config['leds'].get('spi'), led_count=config['leds'].get('qty'))) self.percolator.bingo = self.bingo self.ws_rings = WS2812(2, 2 * 7 + 45) self.ring_lights = Lights(self.ws_rings) self.feed_rollers = [ Jewel7(lights=self.ring_lights[0:7]), Jewel7(lights=self.ring_lights[7:14]) ] self.rr = RingRamp(lights=self.ring_lights[14:], circumference=60, \ bottom=7, \ g=-40.0, ball_check_fun = self.ball_check) # self.zap_balls = False self.set_brightness(31)
def setUp(self): #logging.basicConfig(level=logging.INFO) ws = self.ws = WS2812(1, 8) lights = self.lights = Lights(ws) # Fill the lattice with a recognizable pattern for i, p in enumerate(tg(len(lights), 0)): lat = lights.lattice[i] for j, c in enumerate(p): lat[j] = c # The leds are all clear self.assertEqual(sum(sum(c) for c in ws), 0) self.rr = RingRamp(leds=lights.leds, lattice=lights.lattice, indexed_range=lights.indexed_range)
def __init__(self, write_fun=None, config={}): self.config = config if write_fun is None: @coroutine def write(self, *args): print(*args) self.write = write else: self.write = write_fun self.act_led = pyb.LED(3) self.err_led = pyb.LED(1) self.pkt_led = pyb.LED(2) self.pots = [0] * 4 self.percolator = \ Percolator(WS2812(spi_bus=config['leds'].get('spi'), led_count=config['leds'].get('qty'))) self.percolator.bingo = self.bingo self.ws_rings = WS2812(2, 2*7 + 45) self.ring_lights = Lights(self.ws_rings) self.feed_rollers = [Jewel7(lights=self.ring_lights[0:7]), Jewel7(lights=self.ring_lights[7:14])] self.rr = RingRamp(lights=self.ring_lights[14:], circumference=60, \ bottom=7, \ g=-40.0, ball_check_fun = self.ball_check) # self.zap_balls = False self.set_brightness(31)
class Lightshow: def __init__(self, write_fun=None, config={}): self.config = config if write_fun is None: @coroutine def write(self, *args): print(*args) self.write = write else: self.write = write_fun self.act_led = pyb.LED(3) self.err_led = pyb.LED(1) self.pkt_led = pyb.LED(2) self.pots = [0] * 4 self.percolator = \ Percolator(WS2812(spi_bus=config['leds'].get('spi'), led_count=config['leds'].get('qty'))) self.percolator.bingo = self.bingo self.ws_rings = WS2812(2, 2 * 7 + 45) self.ring_lights = Lights(self.ws_rings) self.feed_rollers = [ Jewel7(lights=self.ring_lights[0:7]), Jewel7(lights=self.ring_lights[7:14]) ] self.rr = RingRamp(lights=self.ring_lights[14:], circumference=60, \ bottom=7, \ g=-40.0, ball_check_fun = self.ball_check) # self.zap_balls = False self.set_brightness(31) def set_brightness(self, v): self.brightness = self.rr.brightness = self.percolator.brightness = v self.feed_rollers[0].brightness = self.feed_rollers[1].brightness = v @coroutine def flash_LED(self, led, dur=1): led.on() yield from sleep(dur) led.off() @coroutine def fuzzle(self, quit_name): # For testing while not getattr(self, quit_name): #yield from self.flash_LED(self.err_led) # More queue-costly but let's us proceed without waiting for photons yield self.flash_LED( self.err_led) # let a coro do it so we can proceed yield from sleep(100) assert getattr(self, quit_name) setattr(self, quit_name, max(getattr(self, quit_name) - 1, 0)) @coroutine def handle_pots(self, b): for i in range(4): self.pots[i] = big_endian_int(b[2 * i:2 * (i + 1)]) yield from self.show_pots() @coroutine def show_pots(self): s = ', '.join("%d" % v for v in self.pots) yield from self.supertitle("Pots: " + s) @coroutine def supertitle(self, text): yield from self.write(b'\x1b[s\x1b[1;1H\x1b[2K') yield from self.write(text) yield from self.write('\x1b[u') @coroutine def perk(self, cli, cmd, rol): sdelay, _, scolor = str(rol, 'ASCII').partition(' ') try: delay = int(sdelay) except: delay = 100 try: color = eval(scolor) except: color = bytes((8, 0, 0)) if not hasattr(self.percolator, 'perk_quit'): self.percolator.perk_quit = 0 yield self.percolator.perk(delay, color) # Launch this and return def ball_check(self, ball, θ, ω): # Checks a Ball and possibly affects it # Return a list of balls to replace it # (e.g. just [ball] to make no changes) rv = [] # if self.zap_balls: # ball.zap = True # rv.append(ball) # if θ > π: # θ -= 2 * π # elif θ <= -2.408554 <= ball.θ: # and ball.ω >= 0: if θ <= -2.408554 <= ball.θ: # and ball.ω >= 0: # crossed off the top of the "C" # ball.zap = True # rv.append(ball) #print("θ=%f, ω=%f" % (θ, ω )) #print("zapped %r" % ball) self.loop.call_soon(self.perk_and_roll(100, ball.color)) #elif θ < 0.0 < ball.θ: # and ball.ω >= 0: #elif θ < 0.0 < ball.θ or θ > 0.0 > ball.θ : # and ball.ω >= 0: elif θ < 0.0 < ball.θ or \ θ > 0.0 > ball.θ and max(abs(θ), abs(ball.θ)) < 1.5: # and ball.ω >= 0: # Crossed the centerline of the drive rollers #print("rollered %r" % ball) #ball.ω = max(ball.ω , 2.08) # # Can't omit this ball, have to zap it for correct rendering # ball.zap = True # rv.append(ball) # Grind this ball up into primary colors color = list(iter(ball.color)) #Below does not grind up fused primaries of same color: #colors = list(v for v in [(color[0], 0, 0), # (0, color[1], 0), # (0, 0, color[2])] # if sum(v)) t = stoichiometric = self.percolator.stoichiometric stoi_primaries = [(t[0], 0, 0), (0, t[1], 0), (0, 0, t[2])] colors = [] for i in range(3): while color[i] >= stoichiometric[i]: colors.append(stoi_primaries[i]) color[i] -= stoichiometric[i] if color[i]: t = [0, 0, 0] t[i] = color[i] colors.append(tuple(t)) assert colors, colors # At least one for c in colors: rv.append(Ball(θ=0.1, ω=rand.gauss(4.5, 0.2), color=c)) #print(rv) else: rv.append(ball) return rv @coroutine def perk_and_roll(self, speed, color, i=None): out_color = yield from self.percolator.perk(speed, color, i) if out_color is not None: ball = Ball(θ=2 * π * -7 / 60, ω=0.3, color=out_color) self.rr.balls.append(ball) #else: # print("perk yielded a None") @coroutine def bingo(self): stars = list(range(7, 63, 7)) p = self.percolator lattice = p.lattice rand.shuffle(stars) for i in stars: yield from sleep(200) color = tuple(lattice[i]) p.set_color_of(i, (0, 0, 0)) i = self.percolator.down(i, rng() & 1) yield self.perk_and_roll(100, color, i) @coroutine def spin_feed_rollers(self): lower, upper = self.feed_rollers lower.center[2] = upper.center[2] = 1 v = 1.0 for i in range(len(lower.gear)): lower.gear[i] = [v, 0, 0] upper.gear[(3 - i) % len(lower.gear)] = [0, v, 0] v *= 0.3 while True: #time = self.loop.time #then = time() lower.gear.cw() upper.gear.ccw() lower.render() upper.render() #now = time() #t = 20 - (now - then) #then = now #yield from sleep(t) yield from sleep(20) @coroutine def manage_brightness(self): a = pyb.ADC(pyb.Pin('Y12')) amb = a.read() / 4096 while True: v = a.read() amb = 0.95 * amb + 0.05 * v / 4096 bv = 254 * amb + 1 self.set_brightness(bv) yield from sleep(123) @coroutine def play(self, cli, cmd, rol): yield self.percolator.play() @coroutine def stop(self, cli, cmd, rol): self.percolator.play_on = False yield @coroutine def master(self): self.loop = yield GetRunningLoop(None) yield self.manage_brightness() yield self.percolator.keep_leds_current(10) for i in range(7, 63, 7): self.percolator.set_color_of(i, self.percolator.stoichiometric) yield self.percolator.bingo() yield self.rr.integrate_continuously() yield self.spin_feed_rollers() while True: yield from self.flash_LED(self.act_led) yield from sleep(1000) def run(self): loop = get_event_loop() loop.run_until_complete(self.master())
class Lightshow: def __init__(self, write_fun=None, config={}): self.config = config if write_fun is None: @coroutine def write(self, *args): print(*args) self.write = write else: self.write = write_fun self.act_led = pyb.LED(3) self.err_led = pyb.LED(1) self.pkt_led = pyb.LED(2) self.pots = [0] * 4 self.percolator = \ Percolator(WS2812(spi_bus=config['leds'].get('spi'), led_count=config['leds'].get('qty'))) self.percolator.bingo = self.bingo self.ws_rings = WS2812(2, 2*7 + 45) self.ring_lights = Lights(self.ws_rings) self.feed_rollers = [Jewel7(lights=self.ring_lights[0:7]), Jewel7(lights=self.ring_lights[7:14])] self.rr = RingRamp(lights=self.ring_lights[14:], circumference=60, \ bottom=7, \ g=-40.0, ball_check_fun = self.ball_check) # self.zap_balls = False self.set_brightness(31) def set_brightness(self, v): self.brightness = self.rr.brightness = self.percolator.brightness = v self.feed_rollers[0].brightness = self.feed_rollers[1].brightness = v @coroutine def flash_LED(self, led, dur=1): led.on() yield from sleep(dur) led.off() @coroutine def fuzzle(self, quit_name): # For testing while not getattr(self, quit_name): #yield from self.flash_LED(self.err_led) # More queue-costly but let's us proceed without waiting for photons yield self.flash_LED(self.err_led) # let a coro do it so we can proceed yield from sleep(100) assert getattr(self, quit_name) setattr(self, quit_name, max(getattr(self, quit_name) - 1, 0)) @coroutine def handle_pots(self, b): for i in range(4): self.pots[i] = big_endian_int(b[2*i:2*(i+1)]) yield from self.show_pots() @coroutine def show_pots(self): s = ', '.join("%d" % v for v in self.pots) yield from self.supertitle("Pots: " + s) @coroutine def supertitle(self, text): yield from self.write(b'\x1b[s\x1b[1;1H\x1b[2K') yield from self.write(text) yield from self.write('\x1b[u') @coroutine def perk(self, cli, cmd, rol): sdelay, _, scolor = str(rol, 'ASCII').partition(' ') try: delay = int(sdelay) except: delay = 100 try: color = eval(scolor) except: color = bytes((8,0,0)) if not hasattr(self.percolator, 'perk_quit'): self.percolator.perk_quit = 0 yield self.percolator.perk(delay, color) # Launch this and return def ball_check(self, ball, θ, ω ): # Checks a Ball and possibly affects it # Return a list of balls to replace it # (e.g. just [ball] to make no changes) rv = [] # if self.zap_balls: # ball.zap = True # rv.append(ball) # if θ > π: # θ -= 2 * π # elif θ <= -2.408554 <= ball.θ: # and ball.ω >= 0: if θ <= -2.408554 <= ball.θ: # and ball.ω >= 0: # crossed off the top of the "C" # ball.zap = True # rv.append(ball) #print("θ=%f, ω=%f" % (θ, ω )) #print("zapped %r" % ball) self.loop.call_soon(self.perk_and_roll(100, ball.color)) #elif θ < 0.0 < ball.θ: # and ball.ω >= 0: #elif θ < 0.0 < ball.θ or θ > 0.0 > ball.θ : # and ball.ω >= 0: elif θ < 0.0 < ball.θ or \ θ > 0.0 > ball.θ and max(abs(θ), abs(ball.θ)) < 1.5: # and ball.ω >= 0: # Crossed the centerline of the drive rollers #print("rollered %r" % ball) #ball.ω = max(ball.ω , 2.08) # # Can't omit this ball, have to zap it for correct rendering # ball.zap = True # rv.append(ball) # Grind this ball up into primary colors color = list(iter(ball.color)) #Below does not grind up fused primaries of same color: #colors = list(v for v in [(color[0], 0, 0), # (0, color[1], 0), # (0, 0, color[2])] # if sum(v)) t = stoichiometric = self.percolator.stoichiometric stoi_primaries = [(t[0], 0, 0), (0, t[1], 0), (0, 0, t[2])] colors = [] for i in range(3): while color[i] >= stoichiometric[i]: colors.append(stoi_primaries[i]) color[i] -= stoichiometric[i] if color[i]: t = [0, 0, 0] t[i] = color[i] colors.append(tuple(t)) assert colors, colors # At least one for c in colors: rv.append(Ball(θ=0.1, ω =rand.gauss(4.5, 0.2), color=c)) #print(rv) else: rv.append(ball) return rv @coroutine def perk_and_roll(self, speed, color, i=None): out_color = yield from self.percolator.perk(speed, color, i) if out_color is not None: ball = Ball(θ = 2*π * -7/60, ω = 0.3, color=out_color) self.rr.balls.append(ball) #else: # print("perk yielded a None") @coroutine def bingo(self): stars = list(range(7, 63, 7)) p = self.percolator lattice = p.lattice rand.shuffle(stars) for i in stars: yield from sleep(200) color = tuple(lattice[i]) p.set_color_of(i, (0,0,0)) i = self.percolator.down(i, rng()&1) yield self.perk_and_roll(100, color, i) @coroutine def spin_feed_rollers(self): lower, upper = self.feed_rollers lower.center[2] = upper.center[2] = 1 v = 1.0 for i in range(len(lower.gear)): lower.gear[i] = [v, 0, 0] upper.gear[(3-i)%len(lower.gear)] = [0, v, 0] v *= 0.3 while True: #time = self.loop.time #then = time() lower.gear.cw() upper.gear.ccw() lower.render() upper.render() #now = time() #t = 20 - (now - then) #then = now #yield from sleep(t) yield from sleep(20) @coroutine def manage_brightness(self): a = pyb.ADC(pyb.Pin('Y12')) amb = a.read()/4096 while True: v = a.read() amb = 0.95*amb + 0.05*v/4096 bv = 254*amb + 1 self.set_brightness(bv) yield from sleep(123) @coroutine def play(self, cli, cmd, rol): yield self.percolator.play() @coroutine def stop(self, cli, cmd, rol): self.percolator.play_on = False yield @coroutine def master(self): self.loop = yield GetRunningLoop(None) yield self.manage_brightness() yield self.percolator.keep_leds_current(10) for i in range(7, 63, 7): self.percolator.set_color_of(i, self.percolator.stoichiometric) yield self.percolator.bingo() yield self.rr.integrate_continuously() yield self.spin_feed_rollers() while True: yield from self.flash_LED(self.act_led) yield from sleep(1000) def run(self): loop = get_event_loop() loop.run_until_complete(self.master())