misc: attempted refactoring of the display support in something less shitty

This commit is contained in:
Simone Margaritelli 2019-10-15 11:50:09 +02:00
parent df33d20cb2
commit 13d68c7c24
30 changed files with 429 additions and 317 deletions

@ -18,7 +18,7 @@ def on_ui_update(ui):
global update_count global update_count
update_count += 1 update_count += 1
if update_count == OPTIONS['refresh_interval']: if update_count == OPTIONS['refresh_interval']:
ui._init_display() ui.init_display()
ui.set('status', "Screen cleaned") ui.set('status', "Screen cleaned")
logging.info("Screen refreshing") logging.info("Screen refreshing")
update_count = 0 update_count = 0

@ -1,13 +1,12 @@
import _thread import _thread
from threading import Lock from threading import Lock
from PIL import Image
import shutil import shutil
import logging import logging
import os
import pwnagotchi, pwnagotchi.plugins as plugins import pwnagotchi, pwnagotchi.plugins as plugins
from pwnagotchi.ui.view import WHITE, View import pwnagotchi.ui.hw as hw
from pwnagotchi.ui.view import View
from http.server import BaseHTTPRequestHandler, HTTPServer from http.server import BaseHTTPRequestHandler, HTTPServer
@ -88,24 +87,15 @@ class VideoHandler(BaseHTTPRequestHandler):
class Display(View): class Display(View):
def __init__(self, config, state={}): def __init__(self, config, state={}):
super(Display, self).__init__(config, state) super(Display, self).__init__(config, hw.display_for(config), state)
self._enabled = config['ui']['display']['enabled'] self._enabled = config['ui']['display']['enabled']
self._rotation = config['ui']['display']['rotation'] self._rotation = config['ui']['display']['rotation']
self._video_enabled = config['ui']['display']['video']['enabled'] self._video_enabled = config['ui']['display']['video']['enabled']
self._video_port = config['ui']['display']['video']['port'] self._video_port = config['ui']['display']['video']['port']
self._video_address = config['ui']['display']['video']['address'] self._video_address = config['ui']['display']['video']['address']
self._display_type = config['ui']['display']['type']
self._display_color = config['ui']['display']['color']
self._render_cb = None
self._display = None
self._httpd = None self._httpd = None
if self._enabled: self.init_display()
self._init_display()
else:
self.on_render(self._on_view_rendered)
logging.warning("display module is disabled")
if self._video_enabled: if self._video_enabled:
_thread.start_new_thread(self._http_serve, ()) _thread.start_new_thread(self._http_serve, ())
@ -119,149 +109,33 @@ class Display(View):
logging.info("could not get ip of usb0, video server not starting") logging.info("could not get ip of usb0, video server not starting")
def is_inky(self): def is_inky(self):
return self._display_type in ('inkyphat', 'inky') return self._implementation.name == 'inky'
def is_papirus(self): def is_papirus(self):
return self._display_type in ('papirus', 'papi') return self._implementation.name == 'papirus'
def is_waveshare_v1(self): def is_waveshare_v1(self):
return self._display_type in ('waveshare_1', 'ws_1', 'waveshare1', 'ws1') return self._implementation.name == 'waveshare_1'
def is_waveshare_v2(self): def is_waveshare_v2(self):
return self._display_type in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2') return self._implementation.name == 'waveshare_2'
def is_oledhat(self): def is_oledhat(self):
return self._display_type in ('oledhat') return self._implementation.name == 'oledhat'
def is_waveshare_any(self): def is_waveshare_any(self):
return self.is_waveshare_v1() or self.is_waveshare_v2() return self.is_waveshare_v1() or self.is_waveshare_v2()
def _init_display(self): def init_display(self):
if self.is_inky(): if self._enabled:
logging.info("initializing inky display") self._implementation.initialize()
from pwnagotchi.ui.inkyphat.inkyphatfast import InkyPHATFast plugins.on('display_setup', self._implementation)
self._display = InkyPHATFast(self._display_color)
self._display.set_border(InkyPHATFast.BLACK)
self._render_cb = self._inky_render
elif self.is_papirus():
logging.info("initializing papirus display")
from pwnagotchi.ui.papirus.epd import EPD
os.environ['EPD_SIZE'] = '2.0'
self._display = EPD()
self._display.clear()
self._render_cb = self._papirus_render
elif self.is_waveshare_v1():
if self._display_color == 'black':
logging.info("initializing waveshare v1 display in monochromatic mode")
from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
self._display = EPD()
self._display.init(self._display.lut_full_update)
self._display.Clear(0xFF)
self._display.init(self._display.lut_partial_update)
self._render_cb = self._waveshare_render
else:
logging.info("initializing waveshare v1 display 3-color mode")
from pwnagotchi.ui.waveshare.v1.epd2in13bc import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
self._render_cb = self._waveshare_bc_render
elif self.is_waveshare_v2():
logging.info("initializing waveshare v2 display")
from pwnagotchi.ui.waveshare.v2.waveshare import EPD
self._display = EPD()
self._display.init(self._display.FULL_UPDATE)
self._display.Clear(WHITE)
self._display.init(self._display.PART_UPDATE)
self._render_cb = self._waveshare_render
elif self.is_oledhat():
logging.info("initializing oledhat display")
from pwnagotchi.ui.waveshare.oledhat.epd import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
self._render_cb = self._oledhat_render
else: else:
logging.critical("unknown display type %s" % self._display_type) logging.warning("display module is disabled")
plugins.on('display_setup', self._display)
self.on_render(self._on_view_rendered) self.on_render(self._on_view_rendered)
def clear(self): def clear(self):
if self._display is None: self._implementation.clear()
logging.error("no display object created")
elif self.is_inky():
self._display.Clear()
elif self.is_papirus():
self._display.clear()
elif self.is_waveshare_any():
self._display.Clear(WHITE)
elif self.is_oledhat():
self._display.clear()
else:
logging.critical("unknown display type %s" % self._display_type)
def _inky_render(self):
if self._display_color != 'mono':
display_colors = 3
else:
display_colors = 2
img_buffer = self._canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
if self._display_color == 'red':
img_buffer.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':
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0, # index 1 is black
255, 255, 0 # index 2 is yellow
])
else:
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0 # index 1 is black
])
self._display.set_image(img_buffer)
try:
self._display.show()
except:
logging.exception("error while rendering on inky")
def _papirus_render(self):
self._display.display(self._canvas)
self._display.partial_update()
def _waveshare_render(self):
buf = self._display.getbuffer(self._canvas)
if self.is_waveshare_v1():
self._display.display(buf)
elif self.is_waveshare_v2():
self._display.displayPartial(buf)
def _oledhat_render(self):
self._display.display(self._canvas)
def _waveshare_bc_render(self):
buf_black = self._display.getbuffer(self._canvas)
# emptyImage = Image.new('1', (self._display.height, self._display.width), 255)
# buf_color = self._display.getbuffer(emptyImage)
# self._display.display(buf_black,buf_color)
# Custom display function that only handles black
# Was included in epd2in13bc.py
self._display.displayBlack(buf_black)
def image(self): def image(self):
img = None img = None
@ -271,8 +145,7 @@ class Display(View):
def _on_view_rendered(self, img): def _on_view_rendered(self, img):
VideoHandler.render(img) VideoHandler.render(img)
if self._enabled: if self._enabled:
self._canvas = (img if self._rotation == 0 else img.rotate(self._rotation)) self._canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
if self._render_cb is not None: if self._implementation is not None:
self._render_cb() self._implementation.render(self._canvas)

@ -0,0 +1,23 @@
from pwnagotchi.ui.hw.inky import Inky
from pwnagotchi.ui.hw.papirus import Papirus
from pwnagotchi.ui.hw.oledhat import OledHat
from pwnagotchi.ui.hw.waveshare1 import WaveshareV1
from pwnagotchi.ui.hw.waveshare2 import WaveshareV2
def display_for(config):
# config has been normalized already in utils.load_config
if config['ui']['display']['type'] == 'inky':
return Inky(config)
elif config['ui']['display']['type'] == 'papirus':
return Papirus(config)
if config['ui']['display']['type'] == 'oledhat':
return OledHat(config)
elif config['ui']['display']['type'] == 'waveshare_1':
return WaveshareV1(config)
elif config['ui']['display']['type'] == 'waveshare_2':
return WaveshareV2(config)

40
pwnagotchi/ui/hw/base.py Normal file

@ -0,0 +1,40 @@
import pwnagotchi.ui.fonts as fonts
class DisplayImpl(object):
def __init__(self, config, name):
self.name = name
self.config = config['ui']['display']
self._layout = {
'width': 0,
'height': 0,
'face': (0, 0),
'name': (0, 0),
'channel': (0, 0),
'aps': (0, 0),
'uptime': (0, 0),
'line1': (0, 0),
'line2': (0, 0),
'friend_face': (0, 0),
'friend_name': (0, 0),
'shakes': (0, 0),
'mode': (0, 0),
# status is special :D
'status': {
'pos': (0, 0),
'font': fonts.Medium,
'max': 20
}
}
def layout(self):
raise NotImplementedError
def initialize(self):
raise NotImplementedError
def render(self, canvas):
raise NotImplementedError
def clear(self):
raise NotImplementedError

72
pwnagotchi/ui/hw/inky.py Normal file

@ -0,0 +1,72 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Inky(DisplayImpl):
def __init__(self, config):
super(Inky, self).__init__(config, 'inky')
self._display = None
def layout(self):
fonts.setup(10, 8, 10, 28)
self._layout['width'] = 212
self._layout['height'] = 104
self._layout['face'] = (0, 37)
self._layout['name'] = (5, 18)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (25, 0)
self._layout['uptime'] = (147, 0)
self._layout['line1'] = [0, 12, 212, 12]
self._layout['line2'] = [0, 92, 212, 92]
self._layout['friend_face'] = (0, 76)
self._layout['friend_name'] = (40, 78)
self._layout['shakes'] = (0, 93)
self._layout['mode'] = (187, 93)
self._layout['status'] = {
'pos': (102, 18),
'font': fonts.Small,
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing inky display")
from pwnagotchi.ui.hw.libs.inkyphat.inkyphatfast import InkyPHATFast
self._display = InkyPHATFast(self.config['color'])
self._display.set_border(InkyPHATFast.BLACK)
def render(self, canvas):
if self.config['color'] != 'mono':
display_colors = 3
else:
display_colors = 2
img_buffer = canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
if self.config['color'] == 'red':
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0, # index 1 is black
255, 0, 0 # index 2 is red
])
elif self.config['color'] == 'yellow':
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0, # index 1 is black
255, 255, 0 # index 2 is yellow
])
else:
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0 # index 1 is black
])
self._display.set_image(img_buffer)
try:
self._display.show()
except:
logging.exception("error while rendering on inky")
def clear(self):
self._display.Clear()

@ -15,7 +15,7 @@
from PIL import Image from PIL import Image
from PIL import ImageOps from PIL import ImageOps
from pwnagotchi.ui.papirus.lm75b import LM75B from pwnagotchi.ui.hw.libs.papirus import LM75B
import re import re
import os import os
import sys import sys

@ -1,7 +1,6 @@
from . import config from . import config
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
import time import time
import numpy as np
Device_SPI = config.Device_SPI Device_SPI = config.Device_SPI
Device_I2C = config.Device_I2C Device_I2C = config.Device_I2C
@ -121,9 +120,9 @@ class SH1106(object):
GPIO.output(self._dc, GPIO.HIGH); GPIO.output(self._dc, GPIO.HIGH);
for i in range(0,self.width):#for(int i=0;i<self.width; i++) for i in range(0,self.width):#for(int i=0;i<self.width; i++)
if(self.Device == Device_SPI): if(self.Device == Device_SPI):
config.spi_writebyte([~pBuf[i+self.width*page]]); config.spi_writebyte([~pBuf[i + self.width * page]]);
else : else :
config.i2c_writebyte(0x40, ~pBuf[i+self.width*page]) config.i2c_writebyte(0x40, ~pBuf[i + self.width * page])

@ -1,10 +1,5 @@
from . import SH1106 from . import SH1106
import time
from . import config from . import config
import traceback
from PIL import Image,ImageDraw,ImageFont
# Display resolution # Display resolution
EPD_WIDTH = 64 EPD_WIDTH = 64

@ -30,7 +30,6 @@
import logging import logging
from . import epdconfig from . import epdconfig
import numpy as np
# Display resolution # Display resolution
EPD_WIDTH = 122 EPD_WIDTH = 122

@ -27,9 +27,7 @@
# THE SOFTWARE. # THE SOFTWARE.
# #
import logging
from . import epdconfig from . import epdconfig
from PIL import Image
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
# import numpy as np # import numpy as np

@ -0,0 +1,45 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class OledHat(DisplayImpl):
def __init__(self, config):
super(OledHat, self).__init__(config, 'oledhat')
self._display = None
def layout(self):
fonts.setup(8, 8, 8, 8)
self._layout['width'] = 128
self._layout['height'] = 64
self._layout['face'] = (0, 32)
self._layout['name'] = (0, 10)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (25, 0)
self._layout['uptime'] = (65, 0)
self._layout['line1'] = [0, 9, 128, 9]
self._layout['line2'] = [0, 53, 128, 53]
self._layout['friend_face'] = (0, 41)
self._layout['friend_name'] = (40, 43)
self._layout['shakes'] = (0, 53)
self._layout['mode'] = (103, 10)
self._layout['status'] = {
'pos': (30, 18),
'font': fonts.Small,
'max': 18
}
return self._layout
def initialize(self):
logging.info("initializing oledhat display")
from pwnagotchi.ui.hw.libs.waveshare.oledhat.epd import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
self._display.display(canvas)
def clear(self):
self._display.clear()

@ -0,0 +1,47 @@
import logging
import os
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Papirus(DisplayImpl):
def __init__(self, config):
super(Papirus, self).__init__(config, 'papirus')
self._display = None
def layout(self):
fonts.setup(10, 8, 10, 23)
self._layout['width'] = 200
self._layout['height'] = 96
self._layout['face'] = (0, 24)
self._layout['name'] = (5, 14)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (25, 0)
self._layout['uptime'] = (135, 0)
self._layout['line1'] = [0, 11, 200, 11]
self._layout['line2'] = [0, 85, 200, 85]
self._layout['friend_face'] = (0, 69)
self._layout['friend_name'] = (40, 71)
self._layout['shakes'] = (0, 86)
self._layout['mode'] = (175, 86)
self._layout['status'] = {
'pos': (85, 14),
'font': fonts.Medium,
'max': 16
}
return self._layout
def initialize(self):
logging.info("initializing papirus display")
from pwnagotchi.ui.hw.libs.papirus.epd import EPD
os.environ['EPD_SIZE'] = '2.0'
self._display = EPD()
self._display.clear()
def render(self, canvas):
self._display.display(canvas)
self._display.partial_update()
def clear(self):
self._display.clear()

@ -0,0 +1,86 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class WaveshareV1(DisplayImpl):
def __init__(self, config):
super(WaveshareV1, self).__init__(config, 'waveshare_1')
self._display = None
def layout(self):
if self.config['color'] == 'black':
fonts.setup(10, 9, 10, 35)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.Medium,
'max': 20
}
else:
fonts.setup(10, 8, 10, 25)
self._layout['width'] = 212
self._layout['height'] = 104
self._layout['face'] = (0, 26)
self._layout['name'] = (5, 15)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['status'] = (91, 15)
self._layout['uptime'] = (147, 0)
self._layout['line1'] = [0, 12, 212, 12]
self._layout['line2'] = [0, 92, 212, 92]
self._layout['friend_face'] = (0, 76)
self._layout['friend_name'] = (40, 78)
self._layout['shakes'] = (0, 93)
self._layout['mode'] = (187, 93)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.Medium,
'max': 14
}
return self._layout
def initialize(self):
if self.config['color'] == 'black':
logging.info("initializing waveshare v1 display in monochromatic mode")
from pwnagotchi.ui.hw.libs.waveshare.v1.epd2in13 import EPD
self._display = EPD()
self._display.init(self._display.lut_full_update)
self._display.Clear(0xFF)
self._display.init(self._display.lut_partial_update)
else:
logging.info("initializing waveshare v1 display 3-color mode")
from pwnagotchi.ui.hw.libs.waveshare.v1.epd2in13bc import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
if self.config['color'] == 'black':
buf = self._display.getbuffer(canvas)
self._display.display(buf)
else:
buf_black = self._display.getbuffer(canvas)
# emptyImage = Image.new('1', (self._display.height, self._display.width), 255)
# buf_color = self._display.getbuffer(emptyImage)
# self._display.display(buf_black,buf_color)
# Custom display function that only handles black
# Was included in epd2in13bc.py
self._display.displayBlack(buf_black)
def clear(self):
self._display.Clear(0xff)

@ -0,0 +1,69 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class WaveshareV2(DisplayImpl):
def __init__(self, config):
super(WaveshareV2, self).__init__(config, 'waveshare_2')
self._display = None
def layout(self):
if self.config['color'] == 'black':
fonts.setup(10, 9, 10, 35)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.Medium,
'max': 20
}
else:
fonts.setup(10, 8, 10, 25)
self._layout['width'] = 212
self._layout['height'] = 104
self._layout['face'] = (0, 26)
self._layout['name'] = (5, 15)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['status'] = (91, 15)
self._layout['uptime'] = (147, 0)
self._layout['line1'] = [0, 12, 212, 12]
self._layout['line2'] = [0, 92, 212, 92]
self._layout['friend_face'] = (0, 76)
self._layout['friend_name'] = (40, 78)
self._layout['shakes'] = (0, 93)
self._layout['mode'] = (187, 93)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.Medium,
'max': 14
}
return self._layout
def initialize(self):
logging.info("initializing waveshare v2 display")
from pwnagotchi.ui.hw.libs.waveshare.v2.waveshare import EPD
self._display = EPD()
self._display.init(self._display.FULL_UPDATE)
self._display.Clear(0xff)
self._display.init(self._display.PART_UPDATE)
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.displayPartial(buf)
def clear(self):
self._display.Clear(0xff)

@ -1,155 +0,0 @@
import pwnagotchi.ui.fonts as fonts
def inkyphat(config, layout):
fonts.setup(10, 8, 10, 28)
layout['width'] = 212
layout['height'] = 104
layout['face'] = (0, 37)
layout['name'] = (5, 18)
layout['channel'] = (0, 0)
layout['aps'] = (25, 0)
layout['uptime'] = (147, 0)
layout['line1'] = [0, 12, 212, 12]
layout['line2'] = [0, 92, 212, 92]
layout['friend_face'] = (0, 76)
layout['friend_name'] = (40, 78)
layout['shakes'] = (0, 93)
layout['mode'] = (187, 93)
layout['status'] = {
'pos': (102, 18),
'font': fonts.Small,
'max': 20
}
return layout
def papirus(config, layout):
fonts.setup(10, 8, 10, 23)
layout['width'] = 200
layout['height'] = 96
layout['face'] = (0, 24)
layout['name'] = (5, 14)
layout['channel'] = (0, 0)
layout['aps'] = (25, 0)
layout['uptime'] = (135, 0)
layout['line1'] = [0, 11, 200, 11]
layout['line2'] = [0, 85, 200, 85]
layout['friend_face'] = (0, 69)
layout['friend_name'] = (40, 71)
layout['shakes'] = (0, 86)
layout['mode'] = (175, 86)
layout['status'] = {
'pos': (85, 14),
'font': fonts.Medium,
'max': 16
}
return layout
def oledhat(config, layout):
fonts.setup(8, 8, 8, 8)
layout['width'] = 128
layout['height'] = 64
layout['face'] = (0, 32)
layout['name'] = (0, 10)
layout['channel'] = (0, 0)
layout['aps'] = (25, 0)
layout['uptime'] = (65, 0)
layout['line1'] = [0, 9, 128, 9]
layout['line2'] = [0, 53, 128, 53]
layout['friend_face'] = (0, 41)
layout['friend_name'] = (40, 43)
layout['shakes'] = (0, 53)
layout['mode'] = (103, 10)
layout['status'] = {
'pos': (30, 18),
'font': fonts.Small,
'max': 18
}
return layout
def waveshare(config, layout):
if config['ui']['display']['color'] == 'black':
fonts.setup(10, 9, 10, 35)
layout['width'] = 250
layout['height'] = 122
layout['face'] = (0, 40)
layout['name'] = (5, 20)
layout['channel'] = (0, 0)
layout['aps'] = (28, 0)
layout['uptime'] = (layout['width'] - 65, 0)
layout['line1'] = [0, int(layout['height'] * .12), layout['width'], int(layout['height'] * .12)]
layout['line2'] = [0, layout['height'] - int(layout['height'] * .12), layout['width'],
layout['height'] - int(layout['height'] * .12)]
layout['friend_face'] = (0, (layout['height'] * 0.88) - 15)
layout['friend_name'] = (40, (layout['height'] * 0.88) - 13)
layout['shakes'] = (0, layout['height'] - int(layout['height'] * .12) + 1)
layout['mode'] = (layout['width'] - 25, layout['height'] - int(layout['height'] * .12) + 1)
else:
fonts.setup(10, 8, 10, 25)
layout['width'] = 212
layout['height'] = 104
layout['face'] = (0, int(layout['height'] / 4))
layout['name'] = (5, int(layout['height'] * .15))
layout['channel'] = (0, 0)
layout['aps'] = (28, 0)
layout['status'] = (int(layout['width'] / 2) - 15, int(layout['height'] * .15))
layout['uptime'] = (layout['width'] - 65, 0)
layout['line1'] = [0, int(layout['height'] * .12), layout['width'], int(layout['height'] * .12)]
layout['line2'] = [0, layout['height'] - int(layout['height'] * .12), layout['width'],
layout['height'] - int(layout['height'] * .12)]
layout['friend_face'] = (0, (layout['height'] * 0.88) - 15)
layout['friend_name'] = (40, (layout['height'] * 0.88) - 13)
layout['shakes'] = (0, layout['height'] - int(layout['height'] * .12) + 1)
layout['mode'] = (layout['width'] - 25, layout['height'] - int(layout['height'] * .12) + 1)
layout['status'] = {
'pos': (125, 20),
'font': fonts.Medium,
'max': (layout['width'] - 125) // 6
}
return layout
def for_display(config):
layout = {
'width': 0,
'height': 0,
'face': (0, 0),
'name': (0, 0),
'channel': (0, 0),
'aps': (0, 0),
'uptime': (0, 0),
'line1': (0, 0),
'line2': (0, 0),
'friend_face': (0, 0),
'friend_name': (0, 0),
'shakes': (0, 0),
'mode': (0, 0),
# status is special :D
'status': {
'pos': (0, 0),
'font': fonts.Medium,
'max': 20
}
}
if config['ui']['display']['type'] in ('inky', 'inkyphat'):
layout = inkyphat(config, layout)
elif config['ui']['display']['type'] in ('papirus', 'papi'):
layout = papirus(config, layout)
if config['ui']['display']['type'] in ('oledhat'):
layout = oledhat(config, layout)
elif config['ui']['display']['type'] in ('ws_1', 'ws1', 'waveshare_1', 'waveshare1',
'ws_2', 'ws2', 'waveshare_2', 'waveshare2'):
layout = waveshare(config, layout)
return layout

@ -10,7 +10,6 @@ from pwnagotchi.voice import Voice
import pwnagotchi.ui.fonts as fonts import pwnagotchi.ui.fonts as fonts
import pwnagotchi.ui.faces as faces import pwnagotchi.ui.faces as faces
import pwnagotchi.ui.layout as layout
from pwnagotchi.ui.components import * from pwnagotchi.ui.components import *
from pwnagotchi.ui.state import State from pwnagotchi.ui.state import State
@ -20,7 +19,7 @@ ROOT = None
class View(object): class View(object):
def __init__(self, config, state={}): def __init__(self, config, impl, state=None):
global ROOT global ROOT
self._render_cbs = [] self._render_cbs = []
@ -29,7 +28,8 @@ class View(object):
self._frozen = False self._frozen = False
self._lock = Lock() self._lock = Lock()
self._voice = Voice(lang=config['main']['lang']) self._voice = Voice(lang=config['main']['lang'])
self._layout = layout.for_display(config) self._implementation = impl
self._layout = impl.layout(config)
self._width = self._layout['width'] self._width = self._layout['width']
self._height = self._layout['height'] self._height = self._layout['height']
self._state = State(state={ self._state = State(state={
@ -70,8 +70,9 @@ class View(object):
font=fonts.Bold, color=BLACK), font=fonts.Bold, color=BLACK),
}) })
for key, value in state.items(): if state:
self._state.set(key, value) for key, value in state.items():
self._state.set(key, value)
plugins.on('ui_setup', self) plugins.on('ui_setup', self)

@ -56,6 +56,26 @@ def load_config(args):
if user_config: if user_config:
config = merge_config(user_config, config) config = merge_config(user_config, config)
# the very first step is to normalize the display name so we don't need dozens of if/elif around
if config['ui']['display']['type'] in ('inky', 'inkyphat'):
config['ui']['display']['type'] = 'inky'
elif config['ui']['display']['type'] in ('papirus', 'papi'):
config['ui']['display']['type'] = 'papirus'
if config['ui']['display']['type'] in ('oledhat'):
config['ui']['display']['type'] = 'oledhat'
elif config['ui']['display']['type'] in ('ws_1', 'ws1', 'waveshare_1', 'waveshare1'):
config['ui']['display']['type'] = 'waveshare_1'
elif config['ui']['display']['type'] in ('ws_2', 'ws2', 'waveshare_2', 'waveshare2'):
config['ui']['display']['type'] = 'waveshare_2'
else:
print("unsupported display type %s" % config['ui']['display']['type'])
exit(1)
return config return config