Skip to content

Instantly share code, notes, and snippets.

Created May 2, 2021
What would you like to do?
Simple Python3 "driver" for the WaveShare PoE Pi HAT with LCD display.
import time
from typing import Optional, List
from PIL import Image
from PIL import ImageDraw
from PIL import ImageOps
from PIL import ImageFont
from smbus import SMBus
class LcdSSD1306:
FONT = ImageFont.truetype("fonts/type_writer.ttf", 7)
def __init__(self, width: int = 128, height: int = 32):
self._w = width
self._h = height
self._pages = int(self._h / 8)
self._addr = 0x3c # 60
self._bus = SMBus(1)
def __setup(self):
"""Bootstrap the display."""
# yapf: disable
sequence = [
0xAE, 0x40, 0xB0, 0xC8, 0x81,
0xFF, 0xA1, 0xA6, 0xA8, 0x1F,
0xD3, 0x00, 0xD5, 0xF0, 0xD9,
0x22, 0xDA, 0x02, 0xDB, 0x49,
0x8D, 0x14, 0xAF
# yapf: enable
for cmd in sequence:
def write_cmd(self, cmd: int):
self._bus.write_byte_data(self._addr, 0x00, cmd)
def write_ram(self, cmd: int):
self._bus.write_byte_data(self._addr, 0x40, cmd)
def _put_buffer(self, *, color: Optional[int] = None, buffer: Optional[List[int]] = None,):
"""Writes pixels to the screen."""
if color is None and buffer is None:
# no options
if color is not None and buffer:
# both options
if color is not None:
buffer = [color] * (self._h * self._w)
for p in range(self._pages):
self.write_cmd(0xB0 + p)
for c in range(self._w):
idx = c + self._w * p
new = buffer[idx]
def flash_image(self, image: Image, for_: float = 2.0, flip: bool = False):
"""Flashes a black and white image on the display for ``for_`` seconds."""
image_a = image.convert('L')
image_b = ImageOps.invert(image_a)
start = time.monotonic()
while time.monotonic() < start + for_:
self.put_image(image_a, flip=flip)
self.put_image(image_b, flip=flip)
self.put_image(image_a, flip=flip)
def write_lines(self, *lines, flip: bool = False, invert: bool = False):
"""Write lines of text to the display."""
if len(lines) == 1 and '\n' in lines[0]:
lines = lines[0].split('\n')
image ='L', (self._w, self._h), 'BLACK')
draw = ImageDraw.Draw(image)
for idx, line in enumerate(lines):
draw.text((0, (8 * idx)), str(line), font=self.FONT, fill='WHITE')
if invert:
image = ImageOps.invert(image)
self.put_image(image, flip=flip)
writelines = write_lines
def put_image(self, image: Image, flip: bool = False):
"""Puts a Pillow.Image buffer on the screen.
``flip`` will re-orient the image 180 degrees.
# create a buffer for the contents that go on the screen
buffer = [0xff] * (self._pages * self._w)
# orient the image
if image.size == (self._h, self._w):
image = image.rotate(90, expand=True)
if flip:
image = image.rotate(180)
# convert image to monochromatic
mono = image.convert('1')
i_w, i_h = mono.size
pixels = mono.load()
# write the pixels to a horizontal screen
for y in range(i_h):
for x in range(i_w):
if pixels[x, y] == 0x00:
buffer[x + int(y / 8) * self._w] &= ~(1 << (y % 8))
def clear_white(self):
"""Fill the screen with white pixels."""
def clear_black(self):
"""Fill the screen with black pixels."""
def close(self):
"""Safely close the I2C bus instance."""
Copy link

blakev commented May 2, 2021

Link to the WaveShare Wiki.


sudo dpkg -i wiringpi-latest.deb
gpio -v

tar zxvf bcm2835-1.60.tar.gz 
cd bcm2835-1.60/
sudo ./configure
sudo make && sudo make check && sudo make install
sudo apt install libopenjp2-7-dev libtiff-dev
pip3 install --user  smbus pillow

Also need to install this font,


screen = LcdSSD1306()
screen.flash_image('extra/sale.png'), 3.0)
screen.writelines('one', 'two', 'three', 'four')


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment