def runprogram(self,filename:str,colour:Colour, inverted:bool, openmode:OpenTransition, displaymode:MessageStyle, closemode:CloseTransition): """ Program a usbfan device with a suitably formatted bitmap """ m1=self.makemessage(filename,colour,openmode,displaymode,closemode,inverted) p = Program((m1,)) d = Device() d.program(p)
def test_checksum(self): self.assertEqual(Program.checksum(b'\x00\x40\x40\x01\xA2\x00\x00\x00'), b'\x00\x40\x40\x01\xA2\x00\x00\x00\x23', "checksum doesn't match reference data") self.assertEqual(Program.checksum(b'\x00\x40\x23\x80\x83\x80\x83\x80'), b'\x00\x40\x23\x80\x83\x80\x83\x80\xE9', "checksum doesn't match reference data") with self.assertRaises(ValueError): Program.checksum('abcdefgh') with self.assertRaises(ValueError): Program.checksum(b'aoeu')
def example1(self): """ Example use """ src="triangle.png" dst="testcvt6.png" pc=PovConvert() pc.OFFSET=180 img=Image.open(src).resize((79,79),Image.BICUBIC) img=pc.getbwimage(img) img.save("tmp.png") img=pc.transformimage(img) img.save(dst) #pc.cvtimage(src,dst) print("Saved as ",dst) m4 = pc.makemessage(dst,Colour.cyan,OpenTransition.All,MessageStyle.Remain, CloseTransition.UpDown,False) p = Program((m4,)) d = Device() d.program(p)
def test_small(self): columns = [Column([True] + [False] * 10, Colour.red)] for _ in range(7): columns.append(Column([False] * 11, Colour.red)) f = Program((Message(columns), )) self.assertEqual(len(f), 1) self.assertIsInstance(f[0], Message) reference_message = ( b'\x00\x40\x40\x01\x22\x00\x00\x00\xA3', b'\x00\x40\x23\xA4\x23\x9A\xA4\xA4\x0C', b'\x00\x40\x23\xA4\xA4\xA4\x84\xA4\x77', b'\x00\x40\x23\x84\xA4\x84\xA4\x84\x37', b'\x00\x40\x23\xA4\x84\xA4\x84\xA4\x57', b'\x00\x40\x23\x84\xA4\x84\xA3\xA4\x56', b'\x00\x40\x23\xA4\xA4\xA4\xA4\xA4\x97', ) for data, reference in zip(f, reference_message): self.assertEqual(data, reference)
def runscript(self,filename, defaults): """ script format: filename colour inverted open display close Arguments left blank or with (-) will use defaults or command line values. # = comments """ if defaults is None: defaults=argparse.Namespace() defaults.inverted=False defaults.open=OpenTransition.LeftRight defaults.close=CloseTransition.RightLeft defaults.display=MessageStyle.Anticlockwise defaults.colour=Colour.white messages=[] with open(filename,"r") as f: for line in f: line=line.strip() if line=="" or line.startswith("#"): continue msg={} msg["filename"]="" msg["inverted"]=defaults.inverted msg["colour"]=defaults.colour msg["open"]=defaults.open msg["close"]=defaults.close msg["display"]=defaults.display args=line.split() msg["filename"]=args[0] if (len(args)>1 and args[1]!="-"): msg["colour"]=self.parseColour(args[1]) if (len(args)>2 and args[2]!="-"): msg["inverted"]=self.parseBool(args[2]) if (len(args)>3 and args[3]!="-"): msg["open"]=self.parseOpen(args[3]) if (len(args)>4 and args[4]!="-"): msg["display"]=self.parseDisplay(args[4]) if (len(args)>5 and args[5]!="-"): msg["close"]=self.parseClose(args[5]) print("Building message: ",msg) messages.append(self.makemessage(msg["filename"],msg["colour"], msg["open"],msg["display"],msg["close"], msg["inverted"])) p = Program(messages) d = Device() d.program(p)
#! /usr/bin/env python3 # -*- coding: utf-8 -*- from usbfan import Colour, Column, Device, Message, Program # A generic "Message" is made up of 1 to 144 "Column" object # A "Column" has 11 boolean pixels and a "Colour" columns = [Column([True] + [False] * 10, Colour.red)] for _ in range(7): columns.append(Column([False] * 11, Colour.red)) p = Program((Message(columns), )) # Open the device and program d = Device() d.program(p)
True if p >= 128 else False for p in img.convert('L').getdata(0) ] # Convert the image into its columns columns = [ Column(img_data[i:i + Column.PIXELS], colour) for i in range(0, len(img_data), Column.PIXELS) ] return columns def makemessage(imagename: str, color: Colour, openmode: OpenTransition, middlemode: MessageStyle, closemode: CloseTransition): return Message(buildimage(imagename, color), middlemode, openmode, closemode) m0 = makemessage("floral.png", Colour.blue, OpenTransition.DownUp, MessageStyle.Anticlockwise, CloseTransition.UpDown) m1 = makemessage("clockface.png", Colour.red, OpenTransition.DownUp, MessageStyle.Flash, CloseTransition.DownUp) m2 = makemessage("pattern.png", Colour.white, OpenTransition.Clockwise, MessageStyle.Flash, CloseTransition.FromMiddle) p = Program((m0, m1, m2)) # Open the device and program d = Device() d.program(p)
from usbfan import Colour, Column, Device, Message, Program def sawtooth(i): j=i % 22; if j>=11: return 21-j return j # A generic "Message" is made up of 1 to 144 "Column" object # A "Column" has 11 boolean pixels and a "Colour" columns=[] rainbow_colours = [Colour.red, Colour.yellow, Colour.green, Colour.cyan, Colour.blue, Colour.magenta] for i in range(144): col = [True] * 11; col[sawtooth(i)]=False; columns.append(Column(col, rainbow_colours[i % 6])) msg=Message(columns) msg.openmode=Message.OPEN_DOWN_UP msg.middlemode=Message.MIDDLE_CLOCKWISE msg.closemode=Message.CLOSE_UP_DOWN p = Program((msg,)) # Open the device and program d = Device() d.program(p)
#! /usr/bin/env python3 # -*- coding: utf-8 -*- from usbfan import Device, Program, TextMessage # A program is made up of a list of Messages # A "TextMessage" is a subclass of the generic Message class p = Program(( TextMessage("Hello, World!"), TextMessage("How is everyone going?"), )) # Open the device and program d = Device() d.program(p)
MessageStyle, OpenTransition, CloseTransition print("MAX_COLUMNS:", Message.MAX_COLUMNS, "x", Column.PIXELS) # -> 144 * 11 pixel # Column.PIXELS # We can cycle the rainbow here and fill all 144 columns rainbow_colours = [ Colour.red, Colour.yellow, Colour.green, Colour.cyan, Colour.blue, Colour.magenta ] rainbow = [ Column([True] * 11, rainbow_colours[i % len(rainbow_colours)]) for i in range(Message.MAX_COLUMNS) ] p = Program(( TextMessage("Hallo Maya & Fabian ...", message_style=MessageStyle.Flash, open_transition=OpenTransition.DownUp, close_transition=CloseTransition.DownUp), Message(rainbow, message_style=MessageStyle.Clockwise, open_transition=OpenTransition.FromMiddle, close_transition=CloseTransition.ToMiddle), )) # Open the device and program d = Device() d.program(p)
return columns def makemessage(imagename: str, colour: Colour, openmode: OpenTransition, messagemode: MessageStyle, closemode: CloseTransition, inverted: bool = False): return Message(buildimage(imagename, colour, inverted), messagemode, openmode, closemode) m0 = makemessage("floral.png", Colour.blue, OpenTransition.DownUp, MessageStyle.Anticlockwise, CloseTransition.UpDown) m1 = makemessage("clockface.png", Colour.red, OpenTransition.DownUp, MessageStyle.Flash, CloseTransition.DownUp) m2 = makemessage("pattern.png", Colour.white, OpenTransition.Clockwise, MessageStyle.Flash, CloseTransition.FromMiddle) m3 = makemessage("clockface.png", Colour.yellow, OpenTransition.Clockwise, MessageStyle.Clockwise, CloseTransition.ToMiddle, True) m4 = makemessage("testcvt5.png", Colour.cyan, OpenTransition.Clockwise, MessageStyle.Clockwise, CloseTransition.ToMiddle, False) #p = Program((m0,m1,m2,m3)) p = Program((m4, )) # Open the device and program d = Device() d.program(p)
for f in sys.argv[1:]: im = Image.open(f) if im.width > Message.MAX_COLUMNS or im.height != Column.PIXELS: print("Image format mismatch.") break img = [] # walk over all pixels for x in range(im.width): # check for most prominent color in this column l = {} c = [] for y in range(im.height): p = map(im.getpixel((x, y))) if p: if p not in l: l[p] = 1 else: l[p] += 1 c.append(p != None) img.append(Column(c, Colour.white if not l else max(l))) imgs = imgs + (Message(img), ) p = Program(imgs) # Open the device and program d = Device() d.program(p)
#! /usr/bin/env python3 # -*- coding: utf-8 -*- from usbfan import Colour, Column, Device, Message, Program, TextMessage # We can cycle the rainbow here and fill all 144 columns rainbow_colours = [Colour.red, Colour.yellow, Colour.green, Colour.cyan, Colour.blue, Colour.magenta] rainbow = [Column([True] * 11, rainbow_colours[i % len(rainbow_colours)]) for i in range(Message.MAX_COLUMNS)] p = Program(( TextMessage("Here comes the rainbow!"), Message(rainbow), )) # Open the device and program d = Device() d.program(p)
def change_slide_event(): global dev, dev_lock slide = request.json['indexh'] print("Slide {}".format(slide)) p = None if slide == 2: # Slide 2: "This" - "Hello CSides" - "Fri 19 Oct 2018" p = Program(( TextMessage("This!"), TextMessage("Hello CSides"), TextMessage("Fri 19 Oct 18"), )) elif slide == 37: # Slide 37: "Single Red Dot" columns = [Column([True] + [False] * 10, Colour.red)] for _ in range(7): columns.append(Column([False] * 11, Colour.red)) p = Program((Message(columns), )) elif slide == 44: # Slide 44: "Two Red Dots" columns = list() columns.append(Column([True] + [False] * 10, Colour.red)) columns.append(Column([True] + [False] * 10, Colour.red)) for _ in range(6): columns.append(Column([False] * 11, Colour.red)) p = Program((Message(columns), )) elif slide == 47: # Slide 47: "Full Vertical Red" columns = [Column([True] * 11, Colour.red)] for _ in range(7): columns.append(Column([False] * 11, Colour.red)) p = Program((Message(columns), )) elif slide == 49: # Slide 49: "Full Vertical Blue" columns = [Column([True] * 11, Colour.blue)] for _ in range(7): columns.append(Column([False] * 11, Colour.red)) p = Program((Message(columns), )) elif slide == 51: # Slide 51: "Full Vertical Green" columns = [Column([True] * 11, Colour.green)] for _ in range(7): columns.append(Column([False] * 11, Colour.red)) p = Program((Message(columns), )) elif slide == 61: # Slide 61: "Questions?" - RAINBOW! rainbow_colours = [ Colour.red, Colour.yellow, Colour.green, Colour.cyan, Colour.blue, Colour.magenta ] rainbow = [ Column([True] * 11, rainbow_colours[i % len(rainbow_colours)]) for i in range(Message.MAX_COLUMNS) ] p = Program(( TextMessage("Questions?"), Message(rainbow), )) if p: with dev_lock: dev.program(p) return ''
def test_large(self): programs = list() for colour in (Colour.red, Colour.green, Colour.blue, Colour.yellow, Colour.magenta, Colour.cyan, Colour.white): columns = [Column([True] + [False] * 10, colour)] for _ in range(14): columns.append(Column([False] * 11, colour)) columns.append(Column([False] * 10 + [True], colour)) programs.append(Message(columns)) f = Program(programs) self.assertEqual(len(f), 7) self.assertIsInstance(f[6], Message) reference_message = (b'\x00\x40\x40\x02\x22\x01\x00\x00\xA5', b'\x00\x40\x23\xA4\x1D\x92\xA4\xA4\xFE', b'\x00\x40\x23\xA4\xA4\xA4\x80\xA4\x73', b'\x00\x40\x23\x84\xA4\x84\xA4\x84\x37', b'\x00\x40\x23\xA4\x84\xA4\x84\xA4\x57', b'\x00\x40\x23\x84\xA4\x84\xA4\x84\x37', b'\x00\x40\x23\xA4\x84\xA4\x84\xA4\x57', b'\x00\x40\x23\x84\xA4\x84\xA4\x84\x37', b'\x00\x40\x23\xA4\x84\xA4\x84\xA3\x56', b'\x00\x40\x23\xA4\xA4\x92\xA4\xA4\x85', b'\x00\x40\x23\xA4\xA4\xA4\x20\xA4\x13', b'\x00\x40\x23\x24\xA4\x24\xA4\x24\x17', b'\x00\x40\x23\xA4\x24\xA4\x24\xA4\x97', b'\x00\x40\x23\x24\xA4\x24\xA4\x24\x17', b'\x00\x40\x23\xA4\x24\xA4\x24\xA4\x97', b'\x00\x40\x23\x24\xA4\x24\xA4\x24\x17', b'\x00\x40\x23\xA4\x24\xA4\x24\xA3\x96', b'\x00\x40\x23\xA4\xA4\x92\xA4\xA4\x85', b'\x00\x40\x23\xA4\xA4\xA4\x60\xA4\x53', b'\x00\x40\x23\x64\xA4\x64\xA4\x64\xD7', b'\x00\x40\x23\xA4\x64\xA4\x64\xA4\x17', b'\x00\x40\x23\x64\xA4\x64\xA4\x64\xD7', b'\x00\x40\x23\xA4\x64\xA4\x64\xA4\x17', b'\x00\x40\x23\x64\xA4\x64\xA4\x64\xD7', b'\x00\x40\x23\xA4\x64\xA4\x64\xA3\x16', b'\x00\x40\x23\xA4\xA4\x92\xA4\xA4\x85', b'\x00\x40\x23\xA4\xA4\xA4\x00\xA4\xF3', b'\x00\x40\x23\x04\xA4\x04\xA4\x04\xB7', b'\x00\x40\x23\xA4\x04\xA4\x04\xA4\x57', b'\x00\x40\x23\x04\xA4\x04\xA4\x04\xB7', b'\x00\x40\x23\xA4\x04\xA4\x04\xA4\x57', b'\x00\x40\x23\x04\xA4\x04\xA4\x04\xB7', b'\x00\x40\x23\xA4\x04\xA4\x04\xA3\x56', b'\x00\x40\x23\xA4\xA4\x92\xA4\xA4\x85', b'\x00\x40\x23\xA4\xA4\xA4\x40\xA4\x33', b'\x00\x40\x23\x44\xA4\x44\xA4\x44\x77', b'\x00\x40\x23\xA4\x44\xA4\x44\xA4\xD7', b'\x00\x40\x23\x44\xA4\x44\xA4\x44\x77', b'\x00\x40\x23\xA4\x44\xA4\x44\xA4\xD7', b'\x00\x40\x23\x44\xA4\x44\xA4\x44\x77', b'\x00\x40\x23\xA4\x44\xA4\x44\xA3\xD6', b'\x00\x40\x23\xA4\xA4\x92\xA4\xA4\x85', b'\x00\x40\x23\xA4\xA4\xA4\xE0\xA4\xD3', b'\x00\x40\x23\xE4\xA4\xE4\xA4\xE4\x57', b'\x00\x40\x23\xA4\xE4\xA4\xE4\xA4\x17', b'\x00\x40\x23\xE4\xA4\xE4\xA4\xE4\x57', b'\x00\x40\x23\xA4\xE4\xA4\xE4\xA4\x17', b'\x00\x40\x23\xE4\xA4\xE4\xA4\xE4\x57', b'\x00\x40\x23\xA4\xE4\xA4\xE4\xA3\x16', b'\x00\x40\x23\xA4\xA4\x92\xA4\xA4\x85', b'\x00\x40\x23\xA4\xA4\xA4\xC0\xA4\xB3', b'\x00\x40\x23\xC4\xA4\xC4\xA4\xC4\xF7', b'\x00\x40\x23\xA4\xC4\xA4\xC4\xA4\xD7', b'\x00\x40\x23\xC4\xA4\xC4\xA4\xC4\xF7', b'\x00\x40\x23\xA4\xC4\xA4\xC4\xA4\xD7', b'\x00\x40\x23\xC4\xA4\xC4\xA4\xC4\xF7', b'\x00\x40\x23\xA4\xC4\xA4\xC4\xA3\xD6', b'\x00\x40\x23\xA4\xA4\xA4\xA4\xA4\x97', b'\x00\x40\x23\xA4\xA4\xA4\xA4\xA4\x97', b'\x00\x40\x23\x64\xA4\xA4\xA4\xA4\x57', b'\x00\x40\x23\xA4\xA4\xA4\xA4\xA4\x97') for data, reference in zip(f, reference_message): self.assertEqual(data, reference)