I2C oled driver mods by NurseJackass

I2C oled config can be added in the config.toml
Default is 128x64 display on i2c address 0x3C

ui.display.type = "i2coled"
ui.display.i2c_addr = 0x3C
ui.display.width = 128
ui.display.height = 64
This commit is contained in:
RasTacsko
2024-04-18 17:39:53 +02:00
parent 9a941c1d46
commit fef442edbb
5 changed files with 57 additions and 33 deletions

View File

@ -3,20 +3,33 @@
# https://github.com/adafruit/Adafruit_Python_SSD1306
# SMBus parts coming from BLavery's lib_oled96 repo:
# https://github.com/BLavery/lib_oled96
# I2C address, width and height import from config.toml made by NurseJackass
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
#
# Default is 128x64 display on i2c address 0x3C
#
# Configure i2c address and dimensions in config.toml:
#
# ui.display.type = "i2coled"
# ui.display.i2c_addr = 0x3C
# ui.display.width = 128
# ui.display.height = 64
#
class I2COled(DisplayImpl):
def __init__(self, config):
self._config = config['ui']['display']
super(I2COled, self).__init__(config, 'i2coled')
def layout(self):
fonts.setup(8, 8, 8, 10, 10, 8)
self._layout['width'] = 128
self._layout['height'] = 64
self._layout['width'] = self._config['width'] if 'width' in self._config else 128
self._layout['height'] = self._config['height'] if 'height' in self._config else 64
self._layout['face'] = (0, 30)
self._layout['name'] = (0, 10)
self._layout['channel'] = (72, 10)
@ -36,10 +49,14 @@ class I2COled(DisplayImpl):
return self._layout
def initialize(self):
logging.info("initializing 128x64 I2C Oled Display on address 0x3C")
logging.info("To change resolution or address check pwnagotchi/ui/hw/libs/i2coled/epd.py")
i2caddr = self._config['i2c_addr'] if 'i2c_addr' in self._config else 0x3C
width = self._config['width'] if 'width' in self._config else 128
height = self._config['height'] if 'height' in self._config else 64
logging.info("initializing %dx%d I2C Oled Display on address 0x%X" % (width, height, i2caddr))
from pwnagotchi.ui.hw.libs.i2coled.epd import EPD
self._display = EPD()
self._display = EPD(address=i2caddr, width=width, height=height)
self._display.Init()
self._display.Clear()

View File

@ -100,13 +100,19 @@ class SSD1306Base(object):
"""Send command byte to display."""
# I2C write.
assert(len(cmd) <= 31)
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
try:
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
except Exception as e:
logging.exception(e)
def data(self, data):
"""Send byte of data to display."""
# I2C write.
for i in range(0, len(data), 31):
self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31]))
try:
for i in range(0, len(data), 31):
self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31]))
except Exception as e:
logging.exception(e)
def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
"""Initialize display."""
@ -116,7 +122,7 @@ class SSD1306Base(object):
self._initialize()
# Turn on the display.
self.command(SSD1306_DISPLAYON)
def ShowImage(self):
"""
The image on the "canvas" is flushed through to the hardware display.
@ -128,10 +134,12 @@ class SSD1306Base(object):
self.command(SSD1306_PAGEADDR)
self.command(0) # Page start address. (0 = reset)
self.command(self._pages-1) # Page end address.
for i in range(0, len(self._buffer), 16):
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
try:
for i in range(0, len(self._buffer), 16):
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
except Exception as e:
logging.exception(e)
def getbuffer(self, image):
"""Set buffer to value of Python Imaging Library image. The image should
be in 1 bit mode and a size equal to the display size.
@ -229,7 +237,7 @@ class SSD1306_128_64(SSD1306Base):
class SSD1306_128_32(SSD1306Base):
def __init__(self, width, height, address=None, bus=None):
# Call base class constructor.
super(SSD1306_128_64, self).__init__(128, 64, address, bus)
super(SSD1306_128_32, self).__init__(128, 32, address, bus)
def _initialize(self):
# 128x32 pixel specific initialization.

View File

@ -8,20 +8,27 @@ EPD_HEIGHT = 64
# disp = SSD1306.SSD1306_128_32(128, 32, address=0x3C)
# disp = SSD1306.SSD1306_96_16(96, 16, address=0x3C)
# If you change for different resolution, you have to modify the layout in pwnagotchi/ui/hw/i2coled.py
disp = SSD1306.SSD1306_128_64(128, 64, address=0x3C)
class EPD(object):
def __init__(self):
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
def __init__(self, address=0x3D, width=EPD_WIDTH, height=EPD_HEIGHT):
self.width = width
self.height = height
# choose subclass based on dimensions
if height == 32:
self.disp = SSD1306.SSD1306_128_32(width, height, address)
elif height == 16:
self.disp = SSD1306.SSD1306_96_16(width, height, address)
else:
self.disp = SSD1306.SSD1306_128_64(width, height, address)
def Init(self):
disp.begin()
self.disp.begin()
def Clear(self):
disp.clear()
self.disp.clear()
def display(self, image):
disp.getbuffer(image)
disp.ShowImage()
self.disp.getbuffer(image)
self.disp.ShowImage()

View File

@ -106,7 +106,7 @@ class SSD1306Base(object):
self._initialize()
# Turn on the display.
self.command(SSD1306_DISPLAYON)
def ShowImage(self):
"""
The image on the "canvas" is flushed through to the hardware display.
@ -118,10 +118,10 @@ class SSD1306Base(object):
self.command(SSD1306_PAGEADDR)
self.command(0) # Page start address. (0 = reset)
self.command(self._pages-1) # Page end address.
for i in range(0, len(self._buffer), 16):
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
def getbuffer(self, image):
"""Set buffer to value of Python Imaging Library image. The image should
be in 1 bit mode and a size equal to the display size.

View File

@ -95,11 +95,8 @@ class ST7789(object):
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
@ -109,7 +106,6 @@ class ST7789(object):
: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))
@ -287,9 +283,7 @@ class ST7789(object):
def begin(self):
"""Set up the display
Deprecated. Included in __init__.
"""
pass
@ -326,9 +320,7 @@ class ST7789(object):
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()