diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml index 540b872..f470b9c 100644 --- a/sdcard/rootfs/root/pwnagotchi/config.yml +++ b/sdcard/rootfs/root/pwnagotchi/config.yml @@ -17,7 +17,7 @@ main: # if not null, filter access points by this regular expression filter: null # cryptographic key for identity - pubkey: /etc/ssh/ssh_host_rsa_key.pub + pubkey: /etc/ssh/ssh_host_rsa_key.pub ai: # if false, only the default 'personality' will be used @@ -36,7 +36,7 @@ ai: vf_coef: 0.25 # entropy coefficient for the loss calculation ent_coef: 0.01 - # maximum value for the gradient clipping + # maximum value for the gradient clipping max_grad_norm: 0.5 # the learning rate learning_rate: 0.0010 @@ -83,7 +83,7 @@ personality: # number of active epochs that triggers the excited state excited_num_epochs: 10 # number of inactive epochs that triggers the bored state - bored_num_epochs: 15 + bored_num_epochs: 15 # number of inactive epochs that triggers the sad state sad_num_epochs: 25 @@ -92,6 +92,10 @@ ui: # ePaper display can update every 3 secs anyway fps: 0.3 display: + # Possible options inkyphat/waveshare + type: 'inkyphat' + # Possible options red/yellow/black (black used for monocromatic displays) + display_color: 'red' enabled: true rotation: 180 video: @@ -115,7 +119,7 @@ bettercap: port: 8081 username: user password: pass - # folder where bettercap stores the WPA handshakes, given that + # folder where bettercap stores the WPA handshakes, given that # wifi.handshakes.aggregate will be set to false and individual # pcap files will be created in order to minimize the chances # of a single pcap file to get corrupted diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py index 5a1d03d..73413ce 100644 --- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py +++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py @@ -19,7 +19,7 @@ class VideoHandler(BaseHTTPRequestHandler): </head> <body> <img src="/ui" id="ui"/> - + <script type="text/javascript"> window.onload = function() { var image = document.getElementById("ui"); @@ -77,6 +77,8 @@ class Display(View): self._video_enabled = config['ui']['display']['video']['enabled'] self._video_port = config['ui']['display']['video']['port'] self._video_address = config['ui']['display']['video']['address'] + self._display_type = config['ui']['display']['type'] + self._display_color = config['ui']['display']['display_color'] self._display = None self._httpd = None self.canvas = None @@ -99,12 +101,18 @@ class Display(View): core.log("could not get ip of usb0, video server not starting") def _init_display(self): - from pwnagotchi.ui.waveshare import EPD - # core.log("display module started") - self._display = EPD() - self._display.init(self._display.FULL_UPDATE) - self._display.Clear(WHITE) - self._display.init(self._display.PART_UPDATE) + if self._display_type == 'inkyphat': + from inky import InkyPHAT + self._display = InkyPHAT(self._display_color) + self._display.set_border(InkyPHAT.BLACK) + else: + from pwnagotchi.ui.waveshare import EPD + # core.log("display module started") + self._display = EPD() + self._display.init(self._display.FULL_UPDATE) + self._display.Clear(WHITE) + self._display.init(self._display.PART_UPDATE) + self.on_render(self._on_view_rendered) def image(self): @@ -119,5 +127,34 @@ class Display(View): if self._enabled: self.canvas = img if self._rotation == 0 else img.rotate(self._rotation) - buf = self._display.getbuffer(self.canvas) - self._display.displayPartial(buf) + if self._display_type == 'inkyphat': + if self._display_color != 'mono': + display_colors = 3 + else: + display_colors = 2 + + imgbuf = self.canvas.convert('RGB').convert('P', palette=1, colors=display_colors) + + if self._display_color == 'red': + imgbuf.putpalette([ + 255, 255, 255, # index 0 is white + 0, 0, 0, # index 1 is black + 255, 0, 0 # index 2 is red + ]) + elif self._display_color == 'yellow': + imgbuf.putpalette([ + 255, 255, 255, # index 0 is white + 0, 0, 0, # index 1 is black + 255, 255, 0 #index 2 is yellow + ]) + else: + imgbuf.putpalette([ + 255, 255, 255, # index 0 is white + 0, 0, 0 # index 1 is black + ]) + + self._display.set_image(imgbuf) + self._display.show() + else: + buf = self._display.getbuffer(self.canvas) + self._display.displayPartial(buf) diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/fonts.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/fonts.py index a8081b8..6f5aa9f 100644 --- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/fonts.py +++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/fonts.py @@ -5,4 +5,4 @@ PATH = '/usr/share/fonts/truetype/dejavu/DejaVuSansMono' Bold = ImageFont.truetype("%s-Bold.ttf" % PATH, 10) BoldSmall = ImageFont.truetype("%s-Bold.ttf" % PATH, 9) Medium = ImageFont.truetype("%s.ttf" % PATH, 10) -Huge = ImageFont.truetype("%s-Bold.ttf" % PATH, 35) +Huge = ImageFont.truetype("%s-Bold.ttf" % PATH, 30) diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py index 899e76a..127c5b7 100644 --- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py +++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py @@ -14,9 +14,6 @@ from pwnagotchi.ui.state import State WHITE = 0xff BLACK = 0x00 -WIDTH = 122 -HEIGHT = 250 - class View(object): def __init__(self, config, state={}): @@ -24,6 +21,14 @@ class View(object): self._config = config self._canvas = None self._lock = Lock() + + if config['ui']['display']['type'] == 'inkyphat': + self._width = 212 + self._height = 104 + else: + self._width = 250 + self.heigth = 122 + self._state = State(state={ 'channel': LabeledValue(color=BLACK, label='CH', value='00', position=(0, 0), label_font=fonts.Bold, text_font=fonts.Medium), @@ -31,27 +36,27 @@ class View(object): text_font=fonts.Medium), #'epoch': LabeledValue(color=BLACK, label='E', value='0000', position=(145, 0), label_font=fonts.Bold, # text_font=fonts.Medium), - 'uptime': LabeledValue(color=BLACK, label='UP', value='00:00:00', position=(185, 0), label_font=fonts.Bold, + 'uptime': LabeledValue(color=BLACK, label='UP', value='00:00:00', position=(self._width - 65, 0), label_font=fonts.Bold, text_font=fonts.Medium), # 'square': Rect([1, 11, 124, 111]), - 'line1': Line([0, 13, 250, 13], color=BLACK), - 'line2': Line([0, 109, 250, 109], color=BLACK), + 'line1': Line([0, int(self._height * .12), self._width, int(self._height * .12)], color=BLACK), + 'line2': Line([0, self._height - int(self._height * .12), self._width, self._height - int(self._height * .12)], color=BLACK), # 'histogram': Histogram([4, 94], color = BLACK), - 'face': Text(value=faces.SLEEP, position=(0, 40), color=BLACK, font=fonts.Huge), + 'face': Text(value=faces.SLEEP, position=(0, int(self._height / 4)), color=BLACK, font=fonts.Huge), 'friend_face': Text(value=None, position=(0, 90), font=fonts.Bold, color=BLACK), 'friend_name': Text(value=None, position=(40, 93), font=fonts.BoldSmall, color=BLACK), - 'name': Text(value='%s>' % 'pwnagotchi', position=(125, 20), color=BLACK, font=fonts.Bold), + 'name': Text(value='%s>' % 'pwnagotchi', position=(int(self._width / 2), int(self._height * .15)), color=BLACK, font=fonts.Bold), # 'face2': Bitmap( '/root/pwnagotchi/data/images/face_happy.bmp', (0, 20)), - 'status': Text(value=voice.default(), position=(125, 35), color=BLACK, font=fonts.Medium), + 'status': Text(value=voice.default(), position=(int(self._width /2), int(self._height * .30)), color=BLACK, font=fonts.Medium), - 'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK, position=(0, 110), label_font=fonts.Bold, + 'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK, position=(0, self._height - int(self._height * .12) + 1), label_font=fonts.Bold, text_font=fonts.Medium), - 'mode': Text(value='AUTO', position=(225, 110), font=fonts.Bold, color=BLACK), + 'mode': Text(value='AUTO', position=(self._width - 25, self._height - int(self._height * .12) + 1), font=fonts.Bold, color=BLACK), }) for key, value in state.items(): @@ -163,8 +168,8 @@ class View(object): for step in range(0, 10): # if we weren't in a normal state before goin - # to sleep, keep that face and status on for - # a while, otherwise the sleep animation will + # to sleep, keep that face and status on for + # a while, otherwise the sleep animation will # always override any minor state change before it if was_normal or step > 5: if sleeping: @@ -293,7 +298,7 @@ class View(object): 1 0.000 0.000 0.000 0.000 ImageMode.py:20(ModeDescriptor) """ with self._lock: - self._canvas = Image.new('1', (HEIGHT, WIDTH), WHITE) + self._canvas = Image.new('1', (self._width, self._height), WHITE) drawer = ImageDraw.Draw(self._canvas) for key, lv in self._state.items(): diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/requirements.txt b/sdcard/rootfs/root/pwnagotchi/scripts/requirements.txt index bde57aa..9b0d40d 100644 --- a/sdcard/rootfs/root/pwnagotchi/scripts/requirements.txt +++ b/sdcard/rootfs/root/pwnagotchi/scripts/requirements.txt @@ -8,3 +8,4 @@ tensorflow tweepy file_read_backwards numpy +inky