Small stuff

Signed-off-by: Jeroen Oudshoorn <oudshoorn.jeroen@gmail.com>

Signed-off-by: Jeroen Oudshoorn <oudshoorn.jeroen@gmail.com>
This commit is contained in:
Jeroen Oudshoorn
2023-07-28 22:15:59 +02:00
parent 5eede9c95d
commit 0f712f0ad2
8 changed files with 31 additions and 526 deletions

View File

@ -1,7 +1,6 @@
import os import os
import logging import logging
import threading import threading
import pwnagotchi.plugins as plugins import pwnagotchi.plugins as plugins
import pwnagotchi.ui.hw as hw import pwnagotchi.ui.hw as hw
from pwnagotchi.ui.view import View from pwnagotchi.ui.view import View
@ -11,12 +10,9 @@ class Display(View):
def __init__(self, config, state={}): def __init__(self, config, state={}):
super(Display, self).__init__(config, hw.display_for(config), state) super(Display, self).__init__(config, hw.display_for(config), state)
config = config['ui']['display'] config = config['ui']['display']
self._enabled = config['enabled'] self._enabled = config['enabled']
self._rotation = config['rotation'] self._rotation = config['rotation']
self.init_display() self.init_display()
self._canvas_next_event = threading.Event() self._canvas_next_event = threading.Event()
self._canvas_next = None self._canvas_next = None
self._render_thread_instance = threading.Thread( self._render_thread_instance = threading.Thread(
@ -43,44 +39,47 @@ class Display(View):
def is_waveshare27inch(self): def is_waveshare27inch(self):
return self._implementation.name == 'waveshare27inch' return self._implementation.name == 'waveshare27inch'
def is_waveshare27inchPartial(self):
return self._implementation.name == 'waveshare27inchPartial'
def is_waveshare29inch(self): def is_waveshare29inch(self):
return self._implementation.name == 'waveshare29inch' return self._implementation.name == 'waveshare29inch'
def is_oledhat(self): def is_oledhat(self):
return self._implementation.name == 'oledhat' return self._implementation.name == 'oledhat'
def is_lcdhat(self): def is_lcdhat(self):
return self._implementation.name == 'lcdhat' return self._implementation.name == 'lcdhat'
def is_dfrobot_v1(self): def is_dfrobot_v1(self):
return self._implementation.name == 'dfrobot_v1' return self._implementation.name == 'dfrobot_v1'
def is_dfrobot_v2(self): def is_dfrobot_v2(self):
return self._implementation.name == 'dfrobot_v2' return self._implementation.name == 'dfrobot_v2'
def is_waveshare144lcd(self): def is_waveshare144lcd(self):
return self._implementation.name == 'waveshare144lcd' return self._implementation.name == 'waveshare144lcd'
def is_waveshare154inch(self): def is_waveshare154inch(self):
return self._implementation.name == 'waveshare154inch' return self._implementation.name == 'waveshare154inch'
def is_waveshare213d(self): def is_waveshare213d(self):
return self._implementation.name == 'waveshare213d' return self._implementation.name == 'waveshare213d'
def is_waveshare213bc(self): def is_waveshare213bc(self):
return self._implementation.name == 'waveshare213bc' return self._implementation.name == 'waveshare213bc'
def is_waveshare35lcd(self): def is_waveshare35lcd(self):
return self._implementation.name == 'waveshare35lcd' return self._implementation.name == 'waveshare35lcd'
def is_spotpear24inch(self): def is_spotpear24inch(self):
return self._implementation.name == 'spotpear24inch' return self._implementation.name == 'spotpear24inch'
def is_displayhatmini(self):
return self._implementation.name == 'displayhatmini'
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()
@ -93,31 +92,36 @@ class Display(View):
logging.warning("display module is disabled") logging.warning("display module is disabled")
self.on_render(self._on_view_rendered) self.on_render(self._on_view_rendered)
def clear(self): def clear(self):
self._implementation.clear() self._implementation.clear()
def image(self): def image(self):
img = None img = None
if self._canvas is not None: if self._canvas is not None:
img = self._canvas if self._rotation == 0 else self._canvas.rotate(-self._rotation) img = self._canvas if self._rotation == 0 else self._canvas.rotate(-self._rotation)
return img return img
def _render_thread(self): def _render_thread(self):
"""Used for non-blocking screen updating.""" """Used for non-blocking screen updating."""
while True: while True:
self._canvas_next_event.wait() self._canvas_next_event.wait()
if self._implementation.name != 'waveshare27inchPartial':
self._canvas_next_event.clear() self._canvas_next_event.clear()
self._implementation.render(self._canvas_next) self._implementation.render(self._canvas_next)
def _on_view_rendered(self, img): def _on_view_rendered(self, img):
try: try:
if self._config['ui']['web']['on_frame'] != '': if self._config['ui']['web']['on_frame'] != '':
os.system(self._config['ui']['web']['on_frame']) os.system(self._config['ui']['web']['on_frame'])
except Exception as e: except Exception as e:
logging.error("%s" % e) logging.error("%s" % e)
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._implementation is not None: if self._implementation is not None:

View File

@ -8,7 +8,6 @@ from pwnagotchi.ui.hw.waveshare1 import WaveshareV1
from pwnagotchi.ui.hw.waveshare2 import WaveshareV2 from pwnagotchi.ui.hw.waveshare2 import WaveshareV2
from pwnagotchi.ui.hw.waveshare3 import WaveshareV3 from pwnagotchi.ui.hw.waveshare3 import WaveshareV3
from pwnagotchi.ui.hw.waveshare27inch import Waveshare27inch from pwnagotchi.ui.hw.waveshare27inch import Waveshare27inch
from pwnagotchi.ui.hw.waveshare27inchPartial import Waveshare27inchPartial
from pwnagotchi.ui.hw.waveshare29inch import Waveshare29inch from pwnagotchi.ui.hw.waveshare29inch import Waveshare29inch
from pwnagotchi.ui.hw.waveshare144lcd import Waveshare144lcd from pwnagotchi.ui.hw.waveshare144lcd import Waveshare144lcd
from pwnagotchi.ui.hw.waveshare154inch import Waveshare154inch from pwnagotchi.ui.hw.waveshare154inch import Waveshare154inch
@ -16,7 +15,7 @@ from pwnagotchi.ui.hw.waveshare213d import Waveshare213d
from pwnagotchi.ui.hw.waveshare213bc import Waveshare213bc from pwnagotchi.ui.hw.waveshare213bc import Waveshare213bc
from pwnagotchi.ui.hw.waveshare35lcd import Waveshare35lcd from pwnagotchi.ui.hw.waveshare35lcd import Waveshare35lcd
from pwnagotchi.ui.hw.spotpear24inch import Spotpear24inch from pwnagotchi.ui.hw.spotpear24inch import Spotpear24inch
from pwnagotchi.ui.hw.displayhatmini import DisplayHatMini
def display_for(config): def display_for(config):
# config has been normalized already in utils.load_config # config has been normalized already in utils.load_config
@ -50,9 +49,6 @@ def display_for(config):
elif config['ui']['display']['type'] == 'waveshare27inch': elif config['ui']['display']['type'] == 'waveshare27inch':
return Waveshare27inch(config) return Waveshare27inch(config)
elif config['ui']['display']['type'] == 'waveshare27inchPartial':
return Waveshare27inchPartial(config)
elif config['ui']['display']['type'] == 'waveshare29inch': elif config['ui']['display']['type'] == 'waveshare29inch':
return Waveshare29inch(config) return Waveshare29inch(config)
@ -73,6 +69,3 @@ def display_for(config):
elif config['ui']['display']['type'] == 'spotpear24inch': elif config['ui']['display']['type'] == 'spotpear24inch':
return Spotpear24inch(config) return Spotpear24inch(config)
elif config['ui']['display']['type'] == 'displayhatmini':
return DisplayHatMini(config)

View File

@ -1,44 +0,0 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class DisplayHatMini(DisplayImpl):
def __init__(self, config):
super(DisplayHatMini, self).__init__(config, 'displayhatmini')
self._display = None
def layout(self):
fonts.setup(12, 10, 12, 70, 25, 9)
self._layout['width'] = 320
self._layout['height'] = 240
self._layout['face'] = (35, 50)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (40, 0)
self._layout['uptime'] = (240, 0)
self._layout['line1'] = [0, 14, 320, 14]
self._layout['line2'] = [0, 220, 320, 220]
self._layout['friend_face'] = (0, 130)
self._layout['friend_name'] = (40, 135)
self._layout['shakes'] = (0, 220)
self._layout['mode'] = (280, 220)
self._layout['status'] = {
'pos': (80, 160),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing Display Hat Mini")
from pwnagotchi.ui.hw.libs.pimoroni.displayhatmini.ST7789 import ST7789
self._display = ST7789(0,1,9,13)
def render(self, canvas):
self._display.display(canvas)
def clear(self):
self._display.clear()

View File

@ -1,360 +0,0 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import numbers
import time
import numpy as np
import spidev
import RPi.GPIO as GPIO
__version__ = '0.0.4'
BG_SPI_CS_BACK = 0
BG_SPI_CS_FRONT = 1
SPI_CLOCK_HZ = 16000000
ST7789_NOP = 0x00
ST7789_SWRESET = 0x01
ST7789_RDDID = 0x04
ST7789_RDDST = 0x09
ST7789_SLPIN = 0x10
ST7789_SLPOUT = 0x11
ST7789_PTLON = 0x12
ST7789_NORON = 0x13
ST7789_INVOFF = 0x20
ST7789_INVON = 0x21
ST7789_DISPOFF = 0x28
ST7789_DISPON = 0x29
ST7789_CASET = 0x2A
ST7789_RASET = 0x2B
ST7789_RAMWR = 0x2C
ST7789_RAMRD = 0x2E
ST7789_PTLAR = 0x30
ST7789_MADCTL = 0x36
ST7789_COLMOD = 0x3A
ST7789_FRMCTR1 = 0xB1
ST7789_FRMCTR2 = 0xB2
ST7789_FRMCTR3 = 0xB3
ST7789_INVCTR = 0xB4
ST7789_DISSET5 = 0xB6
ST7789_GCTRL = 0xB7
ST7789_GTADJ = 0xB8
ST7789_VCOMS = 0xBB
ST7789_LCMCTRL = 0xC0
ST7789_IDSET = 0xC1
ST7789_VDVVRHEN = 0xC2
ST7789_VRHS = 0xC3
ST7789_VDVS = 0xC4
ST7789_VMCTR1 = 0xC5
ST7789_FRCTRL2 = 0xC6
ST7789_CABCCTRL = 0xC7
ST7789_RDID1 = 0xDA
ST7789_RDID2 = 0xDB
ST7789_RDID3 = 0xDC
ST7789_RDID4 = 0xDD
ST7789_GMCTRP1 = 0xE0
ST7789_GMCTRN1 = 0xE1
ST7789_PWCTR6 = 0xFC
class ST7789(object):
"""Representation of an ST7789 TFT LCD."""
def __init__(self, port, cs, dc, backlight, rst=None, width=320,
height=240, rotation=0, invert=True, spi_speed_hz=60 * 1000 * 1000,
offset_left=0,
offset_top=0):
"""Create an instance of the display using SPI communication.
Must provide the GPIO pin number for the D/C pin and the SPI driver.
Can optionally provide the GPIO pin number for the reset pin as the rst parameter.
:param port: SPI port number
:param cs: SPI chip-select number (0 or 1 for BCM
:param backlight: Pin for controlling backlight
:param rst: Reset pin for ST7789
:param width: Width of display connected to ST7789
:param height: Height of display connected to ST7789
:param rotation: Rotation of display connected to ST7789
:param invert: Invert display
:param spi_speed_hz: SPI speed (in Hz)
"""
if rotation not in [0, 90, 180, 270]:
raise ValueError("Invalid rotation {}".format(rotation))
if width != height and rotation in [90, 270]:
raise ValueError("Invalid rotation {} for {}x{} resolution".format(rotation, width, height))
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
self._spi = spidev.SpiDev(port, cs)
self._spi.mode = 0
self._spi.lsbfirst = False
self._spi.max_speed_hz = spi_speed_hz
self._dc = dc
self._rst = rst
self._width = width
self._height = height
self._rotation = rotation
self._invert = invert
self._offset_left = offset_left
self._offset_top = offset_top
# Set DC as output.
GPIO.setup(dc, GPIO.OUT)
# Setup backlight as output (if provided).
self._backlight = backlight
if backlight is not None:
GPIO.setup(backlight, GPIO.OUT)
GPIO.output(backlight, GPIO.LOW)
time.sleep(0.1)
GPIO.output(backlight, GPIO.HIGH)
# Setup reset as output (if provided).
if rst is not None:
GPIO.setup(self._rst, GPIO.OUT)
self.reset()
self._init()
def send(self, data, is_data=True, chunk_size=4096):
"""Write a byte or array of bytes to the display. Is_data parameter
controls if byte should be interpreted as display data (True) or command
data (False). Chunk_size is an optional size of bytes to write in a
single SPI transaction, with a default of 4096.
"""
# Set DC low for command, high for data.
GPIO.output(self._dc, is_data)
# Convert scalar argument to list so either can be passed as parameter.
if isinstance(data, numbers.Number):
data = [data & 0xFF]
# Write data a chunk at a time.
for start in range(0, len(data), chunk_size):
end = min(start + chunk_size, len(data))
self._spi.xfer(data[start:end])
def set_backlight(self, value):
"""Set the backlight on/off."""
if self._backlight is not None:
GPIO.output(self._backlight, value)
@property
def width(self):
return self._width if self._rotation == 0 or self._rotation == 180 else self._height
@property
def height(self):
return self._height if self._rotation == 0 or self._rotation == 180 else self._width
def command(self, data):
"""Write a byte or array of bytes to the display as command data."""
self.send(data, False)
def data(self, data):
"""Write a byte or array of bytes to the display as display data."""
self.send(data, True)
def reset(self):
"""Reset the display, if reset pin is connected."""
if self._rst is not None:
GPIO.output(self._rst, 1)
time.sleep(0.500)
GPIO.output(self._rst, 0)
time.sleep(0.500)
GPIO.output(self._rst, 1)
time.sleep(0.500)
def _init(self):
# Initialize the display.
self.command(ST7789_SWRESET) # Software reset
time.sleep(0.150) # delay 150 ms
self.command(ST7789_MADCTL)
self.data(0x70)
self.command(ST7789_FRMCTR2) # Frame rate ctrl - idle mode
self.data(0x0C)
self.data(0x0C)
self.data(0x00)
self.data(0x33)
self.data(0x33)
self.command(ST7789_COLMOD)
self.data(0x05)
self.command(ST7789_GCTRL)
self.data(0x14)
self.command(ST7789_VCOMS)
self.data(0x37)
self.command(ST7789_LCMCTRL) # Power control
self.data(0x2C)
self.command(ST7789_VDVVRHEN) # Power control
self.data(0x01)
self.command(ST7789_VRHS) # Power control
self.data(0x12)
self.command(ST7789_VDVS) # Power control
self.data(0x20)
self.command(0xD0)
self.data(0xA4)
self.data(0xA1)
self.command(ST7789_FRCTRL2)
self.data(0x0F)
self.command(ST7789_GMCTRP1) # Set Gamma
self.data(0xD0)
self.data(0x04)
self.data(0x0D)
self.data(0x11)
self.data(0x13)
self.data(0x2B)
self.data(0x3F)
self.data(0x54)
self.data(0x4C)
self.data(0x18)
self.data(0x0D)
self.data(0x0B)
self.data(0x1F)
self.data(0x23)
self.command(ST7789_GMCTRN1) # Set Gamma
self.data(0xD0)
self.data(0x04)
self.data(0x0C)
self.data(0x11)
self.data(0x13)
self.data(0x2C)
self.data(0x3F)
self.data(0x44)
self.data(0x51)
self.data(0x2F)
self.data(0x1F)
self.data(0x1F)
self.data(0x20)
self.data(0x23)
if self._invert:
self.command(ST7789_INVON) # Invert display
else:
self.command(ST7789_INVOFF) # Don't invert display
self.command(ST7789_SLPOUT)
self.command(ST7789_DISPON) # Display on
time.sleep(0.100) # 100 ms
def begin(self):
"""Set up the display
Deprecated. Included in __init__.
"""
pass
def set_window(self, x0=0, y0=0, x1=None, y1=None):
"""Set the pixel address window for proceeding drawing commands. x0 and
x1 should define the minimum and maximum x pixel bounds. y0 and y1
should define the minimum and maximum y pixel bound. If no parameters
are specified the default will be to update the entire display from 0,0
to width-1,height-1.
"""
if x1 is None:
x1 = self._width - 1
if y1 is None:
y1 = self._height - 1
y0 += self._offset_top
y1 += self._offset_top
x0 += self._offset_left
x1 += self._offset_left
self.command(ST7789_CASET) # Column addr set
self.data(x0 >> 8)
self.data(x0 & 0xFF) # XSTART
self.data(x1 >> 8)
self.data(x1 & 0xFF) # XEND
self.command(ST7789_RASET) # Row addr set
self.data(y0 >> 8)
self.data(y0 & 0xFF) # YSTART
self.data(y1 >> 8)
self.data(y1 & 0xFF) # YEND
self.command(ST7789_RAMWR) # write to RAM
def display(self, image):
"""Write the provided image to the hardware.
:param image: Should be RGB format and the same dimensions as the display hardware.
"""
# Set address bounds to entire display.
self.set_window()
# Convert image to 16bit RGB565 format and
# flatten into bytes.
pixelbytes = self.image_to_data(image, self._rotation)
# Write data to hardware.
for i in range(0, len(pixelbytes), 4096):
self.data(pixelbytes[i:i + 4096])
def image_to_data(self, image, rotation=0):
if not isinstance(image, np.ndarray):
image = np.array(image.convert('RGB'))
# Rotate the image
pb = np.rot90(image, rotation // 90).astype('uint16')
# Mask and shift the 888 RGB into 565 RGB
red = (pb[..., [0]] & 0xf8) << 8
green = (pb[..., [1]] & 0xfc) << 3
blue = (pb[..., [2]] & 0xf8) >> 3
# Stick 'em together
result = red | green | blue
# Output the raw bytes
return result.byteswap().tobytes()

View File

@ -1,77 +0,0 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
from PIL import Image
class Waveshare27inchPartial(DisplayImpl):
def __init__(self, config):
super(Waveshare27inchPartial, self).__init__(config, 'waveshare27inchPartial')
self._display = None
self.counter = 0
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 264
self._layout['height'] = 176
self._layout['face'] = (66, 27)
self._layout['name'] = (5, 73)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (199, 0)
self._layout['line1'] = [0, 14, 264, 14]
self._layout['line2'] = [0, 162, 264, 162]
self._layout['friend_face'] = (0, 146)
self._layout['friend_name'] = (40, 146)
self._layout['shakes'] = (0, 163)
self._layout['mode'] = (239, 163)
self._layout['status'] = {
'pos': (38, 93),
'font': fonts.status_font(fonts.Medium),
'max': 40
}
return self._layout
def initialize(self):
logging.info("initializing waveshare v1 2.7 inch display")
from rpi_epd2in7.epd import EPD
self._display = EPD(fast_refresh=True)
self._display.init()
def render(self, canvas):
# have to rotate, because lib work with portrait mode only
# also I have 180 degrees screen rotation inn config, not tested with other valuesjk:w
rotated = canvas.rotate(90, expand=True)
if self.counter == 0:
self._display.smart_update(rotated)
# print invert
# print true image
elif self.counter % 35 == 0:
inverted_image = rotated.point(lambda x: 255-x)
self._display.display_partial_frame(inverted_image, 0, 0, 264, 176, fast=True)
self._display.display_partial_frame(rotated, 0, 0, 264, 176, fast=True)
# partial update full screen
elif self.counter % 7 == 0:
# face + text under
#self._display.display_partial_frame(rotated, 35, 35, 190, 115, fast=True)
# full screen partial update
self._display.display_partial_frame(rotated, 0, 0, 264, 176, fast=True)
# partial update face
self._display.display_partial_frame(rotated, 110, 84, 92, 40, fast=True)
if self.counter >= 100:
self.counter = 0
else:
self.counter += 1
def clear(self):
pass

View File

@ -40,7 +40,6 @@ class Waveshare35lcd(DisplayImpl):
from pwnagotchi.ui.hw.libs.fb import fb from pwnagotchi.ui.hw.libs.fb import fb
self._display = fb self._display = fb
logging.info("initializing waveshare 3,5inch lcd display") logging.info("initializing waveshare 3,5inch lcd display")
self._display.ready_fb(i=0)
self._display.black_scr() self._display.black_scr()
def render(self, canvas): def render(self, canvas):

View File

@ -16,10 +16,8 @@ from pwnagotchi.ui.components import *
from pwnagotchi.ui.state import State from pwnagotchi.ui.state import State
from pwnagotchi.voice import Voice from pwnagotchi.voice import Voice
import RPi.GPIO as GPIO WHITE = 0xff
BLACK = 0x00
WHITE = 0x181010
BLACK = 0xffcccc
ROOT = None ROOT = None
@ -124,7 +122,7 @@ class View(object):
while True: while True:
try: try:
name = self._state.get('name') name = self._state.get('name')
self.set('name', name.rstrip('-').strip() if '-' in name else (name + ' -')) self.set('name', name.rstrip('').strip() if '' in name else (name + ' '))
self.update() self.update()
except Exception as e: except Exception as e:
logging.warning("non fatal error while updating view: %s" % e) logging.warning("non fatal error while updating view: %s" % e)
@ -247,9 +245,9 @@ class View(object):
def wait(self, secs, sleeping=True): def wait(self, secs, sleeping=True):
was_normal = self.is_normal() was_normal = self.is_normal()
part = secs/3.0 part = secs/10.0
for step in range(0, 3): for step in range(0, 10):
# if we weren't in a normal state before going # if we weren't in a normal state before going
# to sleep, keep that face and status on for # to sleep, keep that face and status on for
# a while, otherwise the sleep animation will # a while, otherwise the sleep animation will
@ -259,13 +257,13 @@ class View(object):
if secs > 1: if secs > 1:
self.set('face', faces.SLEEP) self.set('face', faces.SLEEP)
self.set('status', self._voice.on_napping(int(secs))) self.set('status', self._voice.on_napping(int(secs)))
plugins.on('sleep', self, secs)
else: else:
self.set('face', faces.SLEEP2) self.set('face', faces.SLEEP2)
self.set('status', self._voice.on_awakening()) self.set('status', self._voice.on_awakening())
else: else:
self.set('status', self._voice.on_waiting(int(secs))) self.set('status', self._voice.on_waiting(int(secs)))
plugins.on('wait', self, secs)
good_mood = self._agent.in_good_mood() good_mood = self._agent.in_good_mood()
if step % 2 == 0: if step % 2 == 0:
self.set('face', faces.LOOK_R_HAPPY if good_mood else faces.LOOK_R) self.set('face', faces.LOOK_R_HAPPY if good_mood else faces.LOOK_R)
@ -375,9 +373,7 @@ class View(object):
state = self._state state = self._state
changes = state.changes(ignore=self._ignore_changes) changes = state.changes(ignore=self._ignore_changes)
if force or len(changes): if force or len(changes):
colormode = '1' if not 'colormode' in self._config['ui'] else self._config['ui']['colormode'] self._canvas = Image.new('1', (self._width, self._height), WHITE)
backgroundcolor = WHITE if not 'backgroundcolor' in self._config['ui'] else self._config['ui']['backgroundcolor']
self._canvas = Image.new(colormode, (self._width, self._height), backgroundcolor)
drawer = ImageDraw.Draw(self._canvas) drawer = ImageDraw.Draw(self._canvas)
plugins.on('ui_update', self) plugins.on('ui_update', self)

View File

@ -254,9 +254,6 @@ def load_config(args):
elif config['ui']['display']['type'] in ('ws_27inch', 'ws27inch', 'waveshare_27inch', 'waveshare27inch'): elif config['ui']['display']['type'] in ('ws_27inch', 'ws27inch', 'waveshare_27inch', 'waveshare27inch'):
config['ui']['display']['type'] = 'waveshare27inch' config['ui']['display']['type'] = 'waveshare27inch'
elif config['ui']['display']['type'] in ('ws_27inchPartial', 'ws27inchPartial', 'waveshare_27inchPartial', 'waveshare27inchPartial'):
config['ui']['display']['type'] = 'waveshare27inchPartial'
elif config['ui']['display']['type'] in ('ws_29inch', 'ws29inch', 'waveshare_29inch', 'waveshare29inch'): elif config['ui']['display']['type'] in ('ws_29inch', 'ws29inch', 'waveshare_29inch', 'waveshare29inch'):
config['ui']['display']['type'] = 'waveshare29inch' config['ui']['display']['type'] = 'waveshare29inch'
@ -287,9 +284,6 @@ def load_config(args):
elif config['ui']['display']['type'] in ('spotpear24inch'): elif config['ui']['display']['type'] in ('spotpear24inch'):
config['ui']['display']['type'] = 'spotpear24inch' config['ui']['display']['type'] = 'spotpear24inch'
elif config['ui']['display']['type'] in ('displayhatmini'):
config['ui']['display']['type'] = 'displayhatmini'
else: else:
print("unsupported display type %s" % config['ui']['display']['type']) print("unsupported display type %s" % config['ui']['display']['type'])
sys.exit(1) sys.exit(1)
@ -311,11 +305,11 @@ def total_unique_handshakes(path):
def iface_channels(ifname): def iface_channels(ifname):
channels = [] channels = []
phy = subprocess.getoutput("/sbin/iw %s info | grep wiphy | cut -d ' ' -f 2" % ifname) output = subprocess.getoutput("/sbin/iwlist %s freq" % ifname)
output = subprocess.getoutput("/sbin/iw phy%s channels | grep ' MHz' | sed 's/^.*\[//g' | sed s/\].*\$//g" % phy)
for line in output.split("\n"): for line in output.split("\n"):
line = line.strip() line = line.strip()
channels.append(int(line)) if line.startswith("Channel "):
channels.append(int(line.split()[1]))
return channels return channels