Display drivers for SSD1306/SSD1309/SSD1322/SSD1325/SSD1327/SSD1331/SSD1351/SSD1362/SH1106/SH1107/WS0010 OLED matrix displays
npx @tessl/cli install tessl/pypi-luma-oled@3.14.0A Python library providing display drivers for OLED matrix displays with various controllers including SSD1306, SSD1309, SSD1322, SSD1325, SSD1327, SSD1331, SSD1351, SSD1362, SH1106, SH1107, and WS0010. The library supports I2C, SPI, and parallel communication protocols and provides a Pillow-compatible drawing canvas with advanced display capabilities.
pip install luma.oledluma.core>=2.4.1 (automatically installs Pillow for image processing)from luma.oled.device import ssd1306, ssd1331, ssd1322
from luma.core.interface.serial import i2c, spi
from luma.core.render import canvasVersion information:
import luma.oled
print(luma.oled.__version__) # "3.14.0"For specific device types:
# Monochrome devices
from luma.oled.device import ssd1306, ssd1309, sh1106, sh1107
# Color devices
from luma.oled.device import ssd1331, ssd1351
# Greyscale devices
from luma.oled.device import ssd1322, ssd1325, ssd1327, ssd1362, ssd1322_nhd
# Character/text displays
from luma.oled.device import ws0010, winstar_wehfrom luma.core.interface.serial import i2c
from luma.core.render import canvas
from luma.oled.device import ssd1306
from PIL import ImageDraw
# Initialize I2C interface and device
serial = i2c(port=1, address=0x3C)
device = ssd1306(serial)
# Draw to the display using canvas context manager
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline="white", fill="black")
draw.text((30, 40), "Hello World", fill="white")
# Display will be automatically updated when canvas context exitsFor persistent drawing:
# Create reusable canvas
c = canvas(device)
for frame in range(100):
with c as draw:
draw.rectangle(device.bounding_box, outline="white", fill="black")
draw.text((10, 10), f"Frame {frame}", fill="white")The luma.oled library follows a layered architecture:
The design enables developers to easily switch between different display types while maintaining the same drawing and rendering code.
Single-color (usually white/blue) OLED displays supporting 1-bit monochrome rendering with full Pillow drawing capabilities.
class ssd1306:
def __init__(self, serial_interface=None, width=128, height=64, rotate=0, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
class ssd1309(ssd1306): ...
class sh1106:
def __init__(self, serial_interface=None, width=128, height=64, rotate=0, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
class sh1107:
def __init__(self, serial_interface=None, width=64, height=128, rotate=0, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...16-bit color (5-6-5 RGB) OLED displays supporting full-color rendering with framebuffer optimization.
class ssd1331:
def __init__(self, serial_interface=None, width=96, height=64, rotate=0, framebuffer=None, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...
class ssd1351:
def __init__(self, serial_interface=None, width=128, height=128, rotate=0, framebuffer=None, h_offset=0, v_offset=0, bgr=False, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def command(self, cmd, *args): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...4-bit greyscale OLED displays supporting both monochrome and greyscale rendering with automatic RGB to greyscale conversion.
class ssd1322:
def __init__(self, serial_interface=None, width=256, height=64, rotate=0, mode="RGB", framebuffer=None, **kwargs): ...
def display(self, image): ...
def command(self, cmd, *args): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...
class ssd1325:
def __init__(self, serial_interface=None, width=128, height=64, rotate=0, mode="RGB", framebuffer=None, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...
class ssd1327:
def __init__(self, serial_interface=None, width=128, height=128, rotate=0, mode="RGB", framebuffer=None, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...
class ssd1362:
def __init__(self, serial_interface=None, width=256, height=64, rotate=0, mode="RGB", framebuffer=None, **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...
class ssd1322_nhd:
def __init__(self, serial_interface=None, width=128, height=64, rotate=0, mode="RGB", framebuffer=full_frame(), **kwargs): ...
def display(self, image): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...Text-oriented OLED displays with embedded fonts and character-based interface, supporting both graphical and text-based content.
class ws0010:
def __init__(self, serial_interface=None, width=100, height=16, undefined='_', font=None, selected_font=0, exec_time=1e-6 * 50, rotate=0, framebuffer=None, **kwargs): ...
def display(self, image): ...
def get_font(self, ft): ...
def contrast(self, level): ...
def show(self): ...
def hide(self): ...
def clear(self): ...
@property
def text(self) -> str: ...
@text.setter
def text(self, value: str): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def size(self) -> tuple[int, int]: ...
@property
def bounding_box(self) -> tuple[int, int, int, int]: ...
@property
def framebuffer(self): ...
class winstar_weh(ws0010):
def __init__(self, serial_interface=None, width=16, height=2, **kwargs): ...Serial communication interfaces provided by luma.core for connecting to OLED displays via different protocols.
# From luma.core.interface.serial
class i2c:
def __init__(self, port=1, address=0x3C, **kwargs): ...
def command(self, cmd, *args): ...
def data(self, values): ...
class spi:
def __init__(self, port=0, device=0, bus_speed_hz=8000000, **kwargs): ...
def command(self, cmd, *args): ...
def data(self, values): ...
class parallel:
def __init__(self, RS=7, E=8, PINS=[25,24,23,18], **kwargs): ...
def command(self, cmd, *args): ...
def data(self, values): ...# Rotation values
Rotation = int # 0, 1, 2, or 3 (0°, 90°, 180°, 270°)
# Display modes
DisplayMode = str # "1" (monochrome), "RGB" (color/greyscale)
# Framebuffer strategies (from luma.core.framebuffer)
class diff_to_previous: ...
class full_frame: ...
# Bounding box
BoundingBox = tuple[int, int, int, int] # (left, top, right, bottom)
# Image type (from PIL)
Image = PIL.Image.Image