def update_text(self): x, y = self.position time = self.main.status.get('builds_time', timedelta(0)) time -= timedelta(microseconds=time.microseconds) ping = datetime.utcnow() - self.main.last_message ping -= timedelta(microseconds=ping.microseconds) text = { 0: 'Last Ping: {}s'.format(int(ping.total_seconds())), 1: 'Disk Free: {}%'.format(100 * self.main.status.get('disk_free', 0) // self.main.status.get('disk_size', 1)), 2: 'Queue Size: {}'.format(self.main.status.get('builds_pending', 0)), 3: 'Builds/Hour: {}'.format( self.main.status.get('builds_last_hour', 0)), 4: 'Build Time: {}'.format(time), 5: 'Build Size: {}'.format( format_size(self.main.status.get('builds_size', 0))), }[x] self.text = array( draw_text(text, foreground=Color('gray'), padding=(8, 0, 8, 1))) # Ensure the text doesn't "skip" while we're rendering it by starting # the offset cycle at the current position of the offset cycle (unless # it's out of range) last = next(self.offset) if last >= self.text.shape[1] - 8: last = 0 self.offset = iter( cycle(chain(range(last, self.text.shape[1] - 8), range(last))))
def switcher(events, readings, database='environ.rrd'): create_database(database) screens = { (thermometer, 'right'): hygrometer, (hygrometer, 'left'): thermometer, (hygrometer, 'right'): barometer, (barometer, 'left'): hygrometer, } screen = thermometer last_update = None for event, offset, reading in zip(events, bounce(range(8)), readings): anim = 'draw' if event is not None and event.pressed: try: screen = screens[screen, event.direction] anim = event.direction except KeyError: yield array(Color('black')), 'fade' break now = time() if last_update is None or now - last_update > 5: # Only update the database every 5 seconds last_update = now update_database(database, reading) yield screen(offset, reading), anim sleep(0.2)
def update_back(self): x, y = self.position if x == 0: ping = 64 * max(timedelta(0), min(timedelta(seconds=30), datetime.utcnow() - self.main.last_message)).total_seconds() / 30 self.back = array([ c if i <= ping else Color('black') for i in range(64) for c in (self.ping_grad[min(63, int(ping))],) ]) self.back = np.flipud(self.back) elif x == 1: disk = ( 64 * self.main.status.get('disk_free', 0) / self.main.status.get('disk_size', 1)) self.back = array([ c if i < int(disk) else c * Lightness(disk - int(disk)) if i < disk else Color('black') for i in range(64) for c in (self.disk_grad[min(63, int(disk))],) ]) self.back = np.flipud(self.back) elif x == 2: pkgs = min( 64, self.main.status.get('builds_pending', 0)) self.back = array([ Color('blue') if i < pkgs else Color('black') for i in range(64) ]) self.back = np.flipud(self.back) elif x == 3: bph = ( 64 * self.main.status.get('builds_last_hour', 0) / 1000) self.back = array([ Color('blue') if i < int(bph) else Color('blue') * Lightness(bph - int(bph)) if i < bph else Color('black') for i in range(64) ]) self.back = np.flipud(self.back) else: self.back = array(Color('black'))
def __iter__(self): waiting = array( draw_text('Waiting for connection', padding=(8, 0, 8, 1))) for offset in cycle(range(waiting.shape[1] - 8)): if self.connected: break yield waiting[:, offset:offset + 8] buf = array(Color('black')) pulse = iter(bounce(range(10))) while True: x, y = self.position with self.watch_selection(): self.slaves.prune() buf[:] = Color('black') self._render_stats(buf) self._render_slaves(buf, next(pulse)) yield buf
def update_text(self): x, y = self.position text = { 0: 'Quit?', 1: 'Reboot?', 2: 'Off?', }[x] self.text = array( draw_text(text, foreground=Color('red'), padding=(8, 0, 8, 1))) self.offset = iter(cycle(range(self.text.shape[1] - 8)))
def update_text(self): x, y = self.position text = { 0: 'Quit?', 1: 'Terminate?', }[x] self.text = array( draw_text(text, foreground=Color('red'), padding=(8, 0, 8, 1))) self.offset = iter( cycle(chain(range(8, self.text.shape[1] - 8), range(8))))
def __iter__(self): buf = array(Color('black')) grad = list(Color('darkblue').gradient(Color('white'), steps=15)) pulse = iter(bounce(range(len(grad)))) while True: offset = next(self.offset) buf[:, :] = self.text[:, offset:offset + 8] buf[:3, :] = Color('darkblue') x, y = self.position buf[:3, x] = grad[next(pulse)] yield buf
def _update_graph(self): self.graph = array(shape=(5, 8)) for x, stat in zip(reversed(range(8)), self.selected.history()): if stat is None: continue # Scale the value to the vertical size value = stat.value * self.graph.shape[0] for y in range(5): self.graph[4 - y, x] = (stat.color if y < int(value) else stat.color * Lightness(value - int(value)) if y < value else Color('black'))
def __call__(self, args=None): parser = terminal.configure_parser(__doc__, log_params=False) parser.add_argument( '--status-queue', metavar='ADDR', default=const.STATUS_QUEUE, help="The address of the queue used to report status to monitors " "(default: %(default)s)") parser.add_argument( '--control-queue', metavar='ADDR', default=const.CONTROL_QUEUE, dest='master_queue', help="The address of the queue a monitor can use to control the " "master (default: %(default)s)") parser.add_argument( '-r', '--rotate', metavar='DEGREES', default=0, type=int, help="The rotation of the HAT in degrees; must be 0 (the default) " "90, 180, or 270") try: config = parser.parse_args(args) config.control_queue = 'inproc://quit' except: # pylint: disable=bare-except return terminal.error_handler(*sys.exc_info()) with SenseHAT() as hat: hat.rotation = config.rotate ctx = transport.Context() quit_queue = ctx.socket(transport.PULL, protocol=protocols.task_control) quit_queue.bind(config.control_queue) try: stick = StickTask(config, hat) stick.start() screen = ScreenTask(config, hat) screen.start() msg, data = quit_queue.recv_msg() assert msg == 'QUIT' #signal.sigwait({signal.SIGINT, signal.SIGTERM}) except KeyboardInterrupt: pass finally: screen.quit() screen.join() stick.quit() stick.join() ctx.close() hat.screen.fade_to(array(Color('black')))
def arrays(moves): a = array(Color('black')) # blank screen x = y = 3 a[y, x] = Color('white') yield a # initial position for dx, dy in moves: a[y, x] = Color('black') x = max(0, min(7, x + dx)) y = max(0, min(7, y + dy)) a[y, x] = Color('white') yield a a[y, x] = Color('black') yield a # end with a blank display
def __iter__(self): buf = array(Color('black')) pulse = iter(bounce(range(10))) render_mode = { 'text': self._render_text, 'graph': self._render_graph, } while True: x, y = self.position buf[:] = Color('black') self._update_stats() self._render_stats(buf, next(pulse)) render_mode[self.mode](buf) yield buf.clip(0, 1)
def thermometer(offset, reading): t = max(0, min(50, reading.temperature)) / 50 * 64 screen = array([ Color('red') if i < int(t) else Color('red') * Red(t - int(t)) if i < t else Color('black') for i in range(64) ]) screen = np.flipud(screen) text = image_to_rgb(draw_text(int(round(reading.temperature)), 'small.pil', foreground=Color('gray'), padding=(0, 0, 0, 3))) screen[:text.shape[0], :text.shape[1]] += text return screen.clip(0, 1)
def barometer(offset, reading): p = (max(950, min(1050, reading.pressure)) - 950) / 100 * 64 screen = array([ Color('green') if i < int(p) else Color('green') * Green(p - int(p)) if i < p else Color('black') for i in range(64) ]) screen = np.flipud(screen) text = image_to_rgb(draw_text(int(round(reading.pressure)), 'small.pil', foreground=Color('gray'), padding=(0, 0, 8, 3))) screen[:text.shape[0], :] += text[:, offset:offset + 8] return screen.clip(0, 1)
def update_text(self): x, y = self.position text, fg, bg = { 0: (self.slave.label, 'white', None), 1: ('ABI:' + self.slave.abi, 'white', None), 2: (self.slave.status, 'white', None), 3: ('Kill?', 'red', 'black'), }[x] self.text = array( draw_text(text, foreground=Color(fg), background=self.slave.color if bg is None else Color(bg), padding=(8, 0, 8, 1))) self.offset = iter( cycle(chain(range(8, self.text.shape[1] - 8), range(8))))
def display(screen, states): try: for anim, data in states: if anim == 'fade': screen.fade_to(data) elif anim == 'zoom': screen.zoom_to(data) elif anim == 'show': screen.array = data elif anim == 'scroll': screen.scroll_text(data, background=Color('red')) else: assert False finally: screen.fade_to(ps.array(Color('black')))
def hygrometer(offset, reading): h = reading.humidity / 100 * 64 screen = array([ Color('#008') if i < int(h) else Color('#008') * Blue(h - int(h)) if i < h else Color('black') for i in range(64) ]) screen = np.flipud(screen) text = image_to_rgb(draw_text('^^' if reading.humidity > 99 else int(round(reading.humidity)), 'small.pil', foreground=Color('gray'), padding=(0, 0, 0, 3))) screen[:text.shape[0], :text.shape[1]] += text return screen.clip(0, 1)
def _update_text(self, *, restart=True): self.text = array( draw_text(self.selected.label, font='small.pil', padding=(8, 3, 8, 0))) if restart or self.offset is None: last = 0 else: # Ensure the text doesn't "skip" while we're rendering it by # starting the offset cycle at the current position of the offset # cycle (unless it's out of range) last = next(self.offset) if last >= self.text.shape[1] - 8: last = 0 self.offset = iter( cycle(chain(range(last, self.text.shape[1] - 8), range(last))))
def __iter__(self): buf = array(Color('black')) pulse = iter(bounce(range(15))) methods = ( self._render_ping, self._render_disk, self._render_queue, self._render_slaves, ) while True: buf[:] = Color('black') p = next(pulse) self.slaves.prune() for method in methods: method(buf, p) yield buf
def __call__(self, args=None): parser = terminal.configure_parser(__doc__, log_params=False) parser.add_argument( '--status-queue', metavar='ADDR', default=const.STATUS_QUEUE, help="The address of the queue used to report status to monitors " "(default: %(default)s)") parser.add_argument( '--control-queue', metavar='ADDR', default=const.CONTROL_QUEUE, help="The address of the queue a monitor can use to control the " "master (default: %(default)s)") parser.add_argument( '-r', '--rotate', metavar='DEGREES', default=0, type=int, help="The rotation of the HAT in degrees; must be 0 (the default) " "90, 180, or 270") try: config = parser.parse_args(args) except: # pylint: disable=bare-except return terminal.error_handler(*sys.exc_info()) with SenseHAT() as hat: hat.rotation = config.rotate ctx = zmq.Context() try: stick = StickTask(config, hat) stick.start() screen = ScreenTask(config, hat) screen.start() signal.sigwait({signal.SIGINT, signal.SIGTERM}) except KeyboardInterrupt: pass finally: screen.quit() screen.join() stick.quit() stick.join() ctx.destroy(linger=1000) ctx.term() hat.screen.fade_to(array(Color('black')))
def generate_maze(width, height, colors): walls = generate_walls(width, height) maze = ps.array(shape=(2 * height + 1, 2 * width + 1)) maze[...] = colors['unvisited'] maze[::2, ::2] = colors['wall'] for a, b in walls: ay, ax = a by, bx = b y = 2 * by + 1 x = 2 * bx + 1 if ay == by: maze[y, x - 1] = colors['wall'] else: maze[y - 1, x] = colors['wall'] maze[0, :] = maze[:, 0] = colors['wall'] maze[-1, :] = maze[:, -1] = colors['wall'] maze[-2, -2] = colors['goal'] return maze
def _update_text(self): label = [ 'Last Seen', 'Builds Queue/Build Time', 'Disk Used', 'Swap Used', 'Mem Used', 'CPU Temperature', 'Load Avg', 'Builds Done/Clock Skew', ][self.position[0]] self.text = array( draw_text(label, font='small.pil', foreground=Color('white'), background=Color('black'), padding=(8, 3, 8, 0))) self.offset = iter(cycle(range(self.text.shape[1] - 8)))
def switcher(events, readings): screens = { (thermometer, 'right'): hygrometer, (hygrometer, 'left'): thermometer, (hygrometer, 'right'): barometer, (barometer, 'left'): hygrometer, } screen = thermometer for event, offset, reading in zip(events, bounce(range(8)), readings): anim = 'draw' if event is not None and event.pressed: try: screen = screens[screen, event.direction] anim = event.direction except KeyError: yield array(Color('black')), 'fade' break yield screen(offset, reading), anim sleep(0.2)
def game(maze, colors, moves): height, width = maze.shape y, x = (1, 1) maze[y, x] = colors['ball'] left, right = clamp(x, width) top, bottom = clamp(y, height) yield 'fade', maze[top:bottom, left:right] for delta_y, delta_x in moves: if Color(*maze[y + delta_y, x + delta_x]) != colors['wall']: maze[y, x] = colors['visited'] y += delta_y x += delta_x if Color(*maze[y, x]) == colors['goal']: yield from winners_cup() break else: maze[y, x] = colors['ball'] left, right = clamp(x, width) top, bottom = clamp(y, height) yield 'show', maze[top:bottom, left:right] yield 'fade', ps.array(Color('black'))
from __future__ import division # for py2.x compatibility from pisense import SenseHAT, array from colorzero import Color from time import sleep hat = SenseHAT() offset = 0.0 while True: rainbow = array([ Color(h=(x + y) / 14 + offset, s=1, v=1) for x in range(8) for y in range(8) ]) hat.screen.array = rainbow offset += 0.05 sleep(0.05)
def main(): with SenseHAT() as hat: hat.stick.stream = True for a in switcher(hat.stick, hat.environ): hat.screen.array = a hat.screen.fade_to(array(Color('black')))
def winners_cup(): r = Color('red') y = Color('yellow') W = Color('white') yield 'zoom', ps.array([ r, r, W, y, y, y, r, r, r, r, W, y, y, y, r, r, r, r, W, y, y, y, r, r, r, r, r, W, y, r, r, r, r, r, r, W, y, r, r, r, r, r, r, W, y, r, r, r, r, r, r, W, y, r, r, r, r, r, W, y, y, y, r, r, ]) sleep(2) stopwatch.stop() score = stopwatch.duration score = round(score, 1) yield 'fade', ps.array(r) yield 'scroll', 'You win!' yield 'scroll', (str(score))
def empty_screen_board(): # return an empty board for PiSense return pisense.array([ Color(h=0.0, s=0.0, v=((x + y + 1) % 2) * brightness) for x in range(8) for y in range(8) ])
def winners_cup(): r = Color('red') y = Color('yellow') W = Color('white') yield 'zoom', ps.array([ r, r, W, y, y, y, r, r, r, r, W, y, y, y, r, r, r, r, W, y, y, y, r, r, r, r, r, W, y, r, r, r, r, r, r, W, y, r, r, r, r, r, r, W, y, r, r, r, r, r, r, W, y, r, r, r, r, r, W, y, y, y, r, r, ]) sleep(2) yield 'fade', ps.array(r) yield 'scroll', 'You win!'
def __iter__(self): buf = array(Color('black')) while True: offset = next(self.offset) yield self.text[:, offset:offset + 8]
def __iter__(self): buf = array(Color('black')) while True: offset = next(self.offset) buf[:self.text.shape[0], :] = self.text[:, offset:offset + 8] yield buf.clip(0, 1)