Display drivers for SSD1306/SSD1309/SSD1322/SSD1325/SSD1327/SSD1331/SSD1351/SSD1362/SH1106/SH1107/WS0010 OLED matrix displays
—
Text-oriented OLED displays that support both graphical rendering and character-based text display with embedded fonts. These displays combine the flexibility of graphics with the convenience of character addressing.
Serial interface to a monochrome Winstar WS0010 OLED display with character support, embedded fonts, and both graphical and text modes.
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):
"""
Initialize WS0010 OLED character display.
Parameters:
- serial_interface: Parallel interface (luma.core.interface.serial.parallel)
- width: Number of horizontal pixels (default: 100)
- height: Number of vertical pixels (default: 16)
- undefined: Character to display for missing glyphs (default: '_')
- font: Override internal font with PIL.ImageFont (optional)
- selected_font: Select embedded font table by name/number (default: 0)
- exec_time: Command execution time in seconds (default: 50µs)
- rotate: Rotation value 0-3 (0°, 90°, 180°, 270°) (default: 0)
- framebuffer: Framebuffering strategy (diff_to_previous or full_frame)
"""
def display(self, image):
"""
Display a 1-bit PIL Image on the WS0010 OLED.
Parameters:
- image: PIL.Image in mode "1" (1-bit monochrome)
"""
def get_font(self, ft):
"""
Load embedded font by index or name.
Parameters:
- ft: Font index (int) or name (str)
Returns:
Font object for the specified embedded font
"""
@property
def text(self) -> str:
"""Get the current text content displayed on screen."""
@text.setter
def text(self, value: str):
"""
Set text content to display on screen.
Parameters:
- value: Text string to display, supports newlines
"""Supported Resolutions: (40,8), (40,16), (60,8), (60,16), (80,8), (80,16), (100,8), (100,16)
Available Embedded Fonts:
| Number | Name | Font | Size |
|---|---|---|---|
| 0 | FT00 | English Japanese | 5x8 |
| 1 | FT01 | Western European I | 5x8 |
| 2 | FT10 | English Russian | 5x8 |
| 3 | FT11 | Western European II | 5x8 |
| 4 | FT00_10 | English Japanese | 5x10 |
| 5 | FT01_10 | Western European I | 5x10 |
| 6 | FT10_10 | English Russian | 5x10 |
| 7 | FT11_10 | Western European II | 5x10 |
Usage example:
from luma.core.interface.serial import parallel
from luma.oled.device import ws0010
# Initialize with parallel interface
serial = parallel(RS=7, E=8, PINS=[25, 24, 23, 18])
device = ws0010(serial, width=100, height=16, selected_font='FT01')
# Display text using character interface
device.text = "WS0010 Display\nLine 2 Text"
# Or use graphical interface
with canvas(device) as draw:
draw.text((0, 0), "Graphics Mode", fill="white")
draw.rectangle((0, 8, 100, 16), outline="white")
# Load and use different fonts
font = device.get_font('FT11') # Western European II
device.text = "Çafé naïve résumé"Character-based Winstar WEH OLED display using the WS0010 controller with grid-optimized font rendering.
class winstar_weh(ws0010):
def __init__(self, serial_interface=None, width=16, height=2, **kwargs):
"""
Initialize Winstar WEH character OLED display.
Parameters:
- serial_interface: Parallel interface (luma.core.interface.serial.parallel)
- width: Number of characters per line (default: 16)
- height: Number of lines (default: 2)
- undefined: Character to display for missing glyphs (default: '_')
- font: Override internal font with PIL.ImageFont (optional)
- default_table: Select embedded font table (optional)
- embedded_font: Select font size "5x8" or "5x10" (default: "5x8")
- exec_time: Command execution time in seconds (default: 50µs)
- rotate: Rotation value 0-3 (0°, 90°, 180°, 270°) (default: 0)
- framebuffer: Framebuffering strategy (diff_to_previous or full_frame)
Note: Width/height specified in characters, not pixels.
Internal pixel dimensions are width*5 x height*8.
"""Usage example:
from luma.core.interface.serial import parallel
from luma.oled.device import winstar_weh
# Initialize 16x2 character display
serial = parallel(RS=7, E=8, PINS=[25, 24, 23, 18])
device = winstar_weh(serial, width=16, height=2)
# Display character-based text
device.text = "Line 1 Text\nLine 2 Text"
# Text automatically wraps at character boundaries
device.text = "This is a long line of text that will wrap"Character mode uses the text property for simple text display:
# Character mode - automatic font rendering
device.text = "Hello World!\nSecond Line"
# Supports basic formatting
device.text = "Temperature: 23°C\nHumidity: 65%"
# Unicode characters (if font supports them)
device.text = "Café naïve résumé"Graphical mode provides full drawing capabilities:
# Graphical mode - full PIL drawing
with canvas(device) as draw:
draw.text((0, 0), "Custom Graphics", fill="white")
draw.line([(0, 8), (100, 8)], fill="white")
draw.rectangle((10, 10, 90, 15), outline="white")
draw.point([(5, 5), (95, 5)], fill="white")# Select font during initialization
device = ws0010(serial, selected_font='FT01') # Western European
# Or load font dynamically
font_obj = device.get_font(2) # English Russian (FT10)
# Access font by name or number
font1 = device.get_font('FT11_10') # 5x10 Western European II
font2 = device.get_font(7) # Same font by numberfrom PIL import ImageFont
# Use custom PIL font instead of embedded fonts
custom_font = ImageFont.load("custom.pil")
device = ws0010(serial, font=custom_font)
# Embedded fonts are bypassed when custom font is provided
device.text = "Custom Font Text"Character displays typically use parallel interfaces:
from luma.core.interface.serial import parallel
# Standard parallel configuration
serial = parallel(
RS=7, # Register Select pin
E=8, # Enable pin
PINS=[25, 24, 23, 18] # Data pins (D4-D7 for 4-bit mode)
)
# 8-bit mode (if supported)
serial = parallel(
RS=7, E=8,
PINS=[25, 24, 23, 18, 17, 16, 15, 14] # D0-D7 for 8-bit mode
)import luma.core.error
try:
device = ws0010(serial, width=200, height=200)
except luma.core.error.DeviceDisplayModeError as e:
print(f"Unsupported display mode: {e}")Character displays have longer initialization times:
from time import sleep
# Initialize device
device = ws0010(serial)
# Device automatically sleeps 0.5s during initialization
# Additional delays may be needed for complex setups
sleep(0.1)
device.text = "Ready!"WEH displays have 1-pixel gaps every 5th column:
# WEH displays have grid structure
device = winstar_weh(serial, width=16, height=2)
# Text interface automatically handles grid
device.text = "Grid Aligned"
# For graphics, be aware of grid gaps
with canvas(device) as draw:
# Gaps occur at x = 5, 10, 15, 20, etc.
draw.text((0, 0), "Account for gaps in graphics")# Use appropriate framebuffer for usage pattern
from luma.core.framebuffer import diff_to_previous, full_frame
# For frequently changing text
device = ws0010(serial, framebuffer=diff_to_previous())
# For static or infrequent updates
device = ws0010(serial, framebuffer=full_frame())
# Reset display if needed (4-bit mode only)
# Device automatically resets when in 4-bit mode for synchronizationInstall with Tessl CLI
npx tessl i tessl/pypi-luma-oled