With my newly acquired Orange Pi and with 2 monochrome OLED displays in hands that where for my Raspberry Pi at first. I decided to use them on the Orange Pi. I never tried to use them before, so I didn't know what to expect. The display is a 168x64 monochrome display with a SSD1306 controller, fairly inexpensive, I brought them on eBay for only each $5.88. They are controlled by I2C.
Connection
Apparently I2C works out of the box on the Orange Pi. I did not had to do any configuration at all. The pins are the same than the one on the Raspberry Pi 2. Note that the even pins are on the edge side of the board. You can see that SDA1 is on the pin 3, SCL1 is on the pin 5, ground is on the pin 6 and you can connect Vcc to pin 1 (+3.3V), it should be ok.
Making it work
Making it display something was a little bit more tedious. I wanted something in Python for the ease of use and the flexibility. I also wanted to interface it with Django framework and Tastypie REST API. I didn't found anything really interesting on the web. There is some Adafruit library, but I found it quite obscure and complicated for what I want to achieve. So, from Adafruit library, the technical documentation and some information found on the net, I builded mine. It's very simple, very efficient and only meant to work with the 128x64 SSD1306 display, but it can very easy be hacked to make it work with other screen.
The buffer can be directly altered. But it can also convert a monochrome image from the PIL library, this is the way I use it to display images and text.
Prior to use this module, you will need to install some components
# Install as root
pacman -Syu
pacman -S pip2 i2c-tools
pip2 install smbus
# Optional packages for displaying different fonts
pacman -S freetype2
pip2 install pillow
Here is the class definition.
"""
File: ssd1306.py
Author: Yoann Mailland
Version: 1.0
Date: 20151108
Description: Define the SSD1306Display class to drive OLED monochrome display
using the SSD1306 chip
Licence: MIT
Copyright (c) 2015 Yoann Mailland
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 smbus
class SSD1306_Display:
"""
Class used to drive a SSD1306 OLED Display
over a I2C Bus
"""
def __init__(self, bus=0, addr=0x3C, width=128, height=64):
"""
Class init function
bus: I2C bus number to use (default: 0)
addr: I2C address of the display (default 0x3C)
width: width of display in pixel (default 128)
height: height of display in pixel (default 64)
"""
self.bus = smbus.SMBus(bus)
self.DISPLAY_ADDRESS = addr
# Registers
self.COMMAND_REG = 0x00 # Or 0x80 ?
self.DATA_REG = 0x40
self.DISPLAY_WIDTH = width
self.DISPLAY_HEIGHT = height
self.DISPLAY_PAGE_SIZE = 8
self.DISPLAY_PAGE_LENGTH = self.DISPLAY_PAGE_SIZE * self.DISPLAY_WIDTH
# Commands
self.DISPLAY_OFF = 0xAE
self.DISPLAY_ON = 0xAF
self.DISPLAY_SETDISPLAYCLOCKDIV = 0xD5
self.DISPLAY_SETMULTIPLEX = 0xA8
self.DISPLAY_SETDISPLAYOFFSET = 0xD3
self.DISPLAY_SETSTARTLINE = 0x40
self.DISPLAY_CHARGEPUMP = 0x8D
self.DISPLAY_MEMORYMODE = 0x20
self.DISPLAY_SEGREMAP = 0xA0
self.DISPLAY_COMSCANDEC = 0xC8
self.DISPLAY_INV_DISPLAY_OFF = 0xA6
self.DISPLAY_INV_DISPLAY_ON = 0xA7
self.DISPLAY_ALL_ON_OFF = 0xA4
self.DISPLAY_ALL_ON_ON = 0xA5
self.DISPLAY_SETVCOMDETECT = 0xDB
self.DISPLAY_SETPRECHARGE = 0xD9
self.DISPLAY_SETCONTRAST = 0x81
self.DISPLAY_SETCOMPINS = 0xDA
self.DISPLAY_SET_COL_ADDR = 0x21
self.DISPLAY_SET_PAGE_ADDR = 0x22
# Adde Mode
self.HORIZONTAL_ADDRESSING = 0x00
self.PAGE_ADDRESSING = 0x02
self.BUFFER_SIZE = self.DISPLAY_WIDTH * self.DISPLAY_HEIGHT / 8
self.BUFFER = [0x0] * self.BUFFER_SIZE
# Comminications functions
def writeCommand(self, comm):
"""
Send a Command com to the display
"""
self.bus.write_byte_data(self.DISPLAY_ADDRESS, self.COMMAND_REG, comm)
def writeCommandList(self, comms):
"""
Send all Commands in the given comms list to the display
"""
for comm in comms:
self.bus.write_byte_data(self.DISPLAY_ADDRESS, self.COMMAND_REG, comm)
def writeData(self, byte):
"""
Send a Byte of data to the display
"""
self.bus.write_byte_data(slef.DISPLAY_ADDRESS, self.DATA_REG, byte)
def writeBlockData(self, data):
"""
Send a Block of data to the display
data is a array of Bytes (max length=32)
"""
self.bus.write_i2c_block_data(self.DISPLAY_ADDRESS, self.DATA_REG, data)
# Helper functions
def setContrast(self, con):
"""
Valid value 0x0 to 0xFF
"""
self.writeCommand(self.DISPLAY_SETCONTRAST) # 0x81
self.writeCommand(con)
def setColAddress(self, col=0):
"""
Set the horizontal writing pointer of the SSD8306
"""
self.writeCommand(self.DISPLAY_SET_COL_ADDR) # 0x21
self.writeCommand(col) # Column start address
self.writeCommand(self.DISPLAY_WIDTH-1) #Column end address
def setPageAddress(self, page=0):
"""
Set the page of the writing pointer of the SSD8306
"""
self.writeCommand(self.DISPLAY_SET_PAGE_ADDR) # 0x22
self.writeCommand(page) # Start Page address
self.writeCommand((self.DISPLAY_HEIGHT/self.DISPLAY_PAGE_SIZE)-1) # End Page Address
def initDisplay(self):
"""
Default initialization of the SSD8306
for a 128x64 screen
"""
self.writeCommandList([
self.DISPLAY_OFF,
self.DISPLAY_SETMULTIPLEX,
0x3F,
self.DISPLAY_SETDISPLAYOFFSET,
0x0,
self.DISPLAY_SETSTARTLINE | 0x00 , # Start Line #0
self.DISPLAY_MEMORYMODE , # 0x20
0x00 , # Auto Horizontal addressing
self.DISPLAY_SEGREMAP | 0x1 , # rotate screen 180
self.DISPLAY_COMSCANDEC , # rotate screen 180
self.DISPLAY_SETCOMPINS , # 0xDA
0x12 , # COM sequence (Split)
self.DISPLAY_SETCONTRAST , # 0x81
0xFF,
self.DISPLAY_ALL_ON_OFF , # 0xA4
self.DISPLAY_INV_DISPLAY_OFF , # 0xA6
self.DISPLAY_SETDISPLAYCLOCKDIV , # 0xD5
0x80,
self.DISPLAY_CHARGEPUMP , # 0x8D
0x14 , # Enable Charge Pump (Vcc)
self.DISPLAY_SETPRECHARGE , # 0xD9
0xF1 ,
self.DISPLAY_SETVCOMDETECT , # 0xDB
0x40,
self.DISPLAY_ON # 0xAF
])
def _displayBuffer(self):
"""
Byte by byte data transfer
"""
self.setColAddress()
self.setPageAddress()
for b in self.BUFFER:
self.writeData(b)
def displayBuffer(self):
"""
32 bytes block data transfer
"""
self.setColAddress()
self.setPageAddress()
for i in range(0, len(self.BUFFER), 32):
self.writeBlockData(self.BUFFER[i:(i+32)])
def writeBuffer(self, buff):
"""
Set the internal class buffer to buff
buff: Array of bytes of length width*height
"""
if len(self.BUFFER) == len(buff):
self.BUFFER = buff
def setDisplayON(self):
"""
Turn display ON
"""
self.writeCommand(self.DISPLAY_ON)
def setDisplayOFF(self):
"""
Turn display OFF
"""
self.writeCommand(self.DISPLAY_OFF)
def setDisplayINV(self, b=False):
"""
Activate/Desactivate Inverse Mode
b: True to activate Inverse Mode, False to desactivate
"""
self.writeCommand(
self.DISPLAY_INV_DISPLAY_OFF
if b == False else
self.DISPLAY_INV_DISPLAY_ON
)
def img2buffer(self, img):
"""
Converte a monochrome image of WIDTH*HEIGHT size
(used by PIL) to a buffer readable by the SSD1306
"""
buffer = [0x0] * self.BUFFER_SIZE
offset = [n*self.DISPLAY_WIDTH for n in range(0, 8)]
for p in range(self.DISPLAY_PAGE_SIZE):
start_page = p*self.DISPLAY_PAGE_LENGTH
page_offset = p*self.DISPLAY_WIDTH
for x in range(self.DISPLAY_WIDTH):
buffer[page_offset+x] = \
img[ start_page + x] \
| img[ start_page + offset[1] + x ] << 1 \
| img[ start_page + offset[2] + x ] << 2 \
| img[ start_page + offset[3] + x ] << 3 \
| img[ start_page + offset[4] + x ] << 4 \
| img[ start_page + offset[5] + x ] << 5 \
| img[ start_page + offset[6] + x ] << 6 \
| img[ start_page + offset[7] + x ] << 7
return buffer
To improve the speed and thus the framerate, I use the function write_block of the smbus library, this allow me to send 32 bytes as once instead of sending them one by one. I have been able to achieve 18 fps with this code. It might be possible to boost it by changing the speed of the I2C bus from 100KHz to 200KHz and maybe 400KHz. But this requires some change in the I2C driver. But it seems that drivers are compiled with the Linux Kernel and not as modules. So the only solution would be to recompile the Kernel. This might be the subject of a futur post.
Displaying icons with Font Awesome
A great advantage of being able to write with any fonts is to be able to use a font like Font Awesome to display icons. And Font Awesome has a lot of icons. This is great, bu it might be a bit tiresome to have to look at the cheatsheet each time. To simplify everything I made it easy by making a python dictionary where the key is the name of the icon and the value is the corresponding unicode value of the icon.
# File: fontawesome.py
font_awesome = {
"fa-500px": u'\uf26e',
"fa-adjust": u'\uf042',
"fa-adn": u'\uf170',
"fa-align-center": u'\uf037',
"fa-align-justify": u'\uf039',
"fa-align-left": u'\uf036',
"fa-align-right": u'\uf038',
"fa-amazon": u'\uf270',
"fa-ambulance": u'\uf0f9',
"fa-anchor": u'\uf13d',
"fa-android": u'\uf17b',
"fa-angellist": u'\uf209',
"fa-angle-double-down": u'\uf103',
"fa-angle-double-left": u'\uf100',
"fa-angle-double-right": u'\uf101',
"fa-angle-double-up": u'\uf102',
"fa-angle-down": u'\uf107',
"fa-angle-left": u'\uf104',
"fa-angle-right": u'\uf105',
"fa-angle-up": u'\uf106',
"fa-apple": u'\uf179',
"fa-archive": u'\uf187',
"fa-area-chart": u'\uf1fe',
"fa-arrow-circle-down": u'\uf0ab',
"fa-arrow-circle-left": u'\uf0a8',
"fa-arrow-circle-o-down": u'\uf01a',
"fa-arrow-circle-o-left": u'\uf190',
"fa-arrow-circle-o-right": u'\uf18e',
"fa-arrow-circle-o-up": u'\uf01b',
"fa-arrow-circle-right": u'\uf0a9',
"fa-arrow-circle-up": u'\uf0aa',
"fa-arrow-down": u'\uf063',
"fa-arrow-left": u'\uf060',
"fa-arrow-right": u'\uf061',
"fa-arrow-up": u'\uf062',
"fa-arrows": u'\uf047',
"fa-arrows-alt": u'\uf0b2',
"fa-arrows-h": u'\uf07e',
"fa-arrows-v": u'\uf07d',
"fa-asterisk": u'\uf069',
"fa-at": u'\uf1fa',
"fa-automobile": u'\uf1b9',
"fa-backward": u'\uf04a',
"fa-balance-scale": u'\uf24e',
"fa-ban": u'\uf05e',
"fa-bank": u'\uf19c',
"fa-bar-chart": u'\uf080',
"fa-bar-chart-o": u'\uf080',
"fa-barcode": u'\uf02a',
"fa-bars": u'\uf0c9',
"fa-battery-0": u'\uf244',
"fa-battery-1": u'\uf243',
"fa-battery-2": u'\uf242',
"fa-battery-3": u'\uf241',
"fa-battery-4": u'\uf240',
"fa-battery-empty": u'\uf244',
"fa-battery-full": u'\uf240',
"fa-battery-half": u'\uf242',
"fa-battery-quarter": u'\uf243',
"fa-battery-three-quarters": u'\uf241',
"fa-bed": u'\uf236',
"fa-beer": u'\uf0fc',
"fa-behance": u'\uf1b4',
"fa-behance-square": u'\uf1b5',
"fa-bell": u'\uf0f3',
"fa-bell-o": u'\uf0a2',
"fa-bell-slash": u'\uf1f6',
"fa-bell-slash-o": u'\uf1f7',
"fa-bicycle": u'\uf206',
"fa-binoculars": u'\uf1e5',
"fa-birthday-cake": u'\uf1fd',
"fa-bitbucket": u'\uf171',
"fa-bitbucket-square": u'\uf172',
"fa-bitcoin": u'\uf15a',
"fa-black-tie": u'\uf27e',
"fa-bold": u'\uf032',
"fa-bolt": u'\uf0e7',
"fa-bomb": u'\uf1e2',
"fa-book": u'\uf02d',
"fa-bookmark": u'\uf02e',
"fa-bookmark-o": u'\uf097',
"fa-briefcase": u'\uf0b1',
"fa-btc": u'\uf15a',
"fa-bug": u'\uf188',
"fa-building": u'\uf1ad',
"fa-building-o": u'\uf0f7',
"fa-bullhorn": u'\uf0a1',
"fa-bullseye": u'\uf140',
"fa-bus": u'\uf207',
"fa-buysellads": u'\uf20d',
"fa-cab": u'\uf1ba',
"fa-calculator": u'\uf1ec',
"fa-calendar": u'\uf073',
"fa-calendar-check-o": u'\uf274',
"fa-calendar-minus-o": u'\uf272',
"fa-calendar-o": u'\uf133',
"fa-calendar-plus-o": u'\uf271',
"fa-calendar-times-o": u'\uf273',
"fa-camera": u'\uf030',
"fa-camera-retro": u'\uf083',
"fa-car": u'\uf1b9',
"fa-caret-down": u'\uf0d7',
"fa-caret-left": u'\uf0d9',
"fa-caret-right": u'\uf0da',
"fa-caret-square-o-down": u'\uf150',
"fa-caret-square-o-left": u'\uf191',
"fa-caret-square-o-right": u'\uf152',
"fa-caret-square-o-up": u'\uf151',
"fa-caret-up": u'\uf0d8',
"fa-cart-arrow-down": u'\uf218',
"fa-cart-plus": u'\uf217',
"fa-cc": u'\uf20a',
"fa-cc-amex": u'\uf1f3',
"fa-cc-diners-club": u'\uf24c',
"fa-cc-discover": u'\uf1f2',
"fa-cc-jcb": u'\uf24b',
"fa-cc-mastercard": u'\uf1f1',
"fa-cc-paypal": u'\uf1f4',
"fa-cc-stripe": u'\uf1f5',
"fa-cc-visa": u'\uf1f0',
"fa-certificate": u'\uf0a3',
"fa-chain": u'\uf0c1',
"fa-chain-broken": u'\uf127',
"fa-check": u'\uf00c',
"fa-check-circle": u'\uf058',
"fa-check-circle-o": u'\uf05d',
"fa-check-square": u'\uf14a',
"fa-check-square-o": u'\uf046',
"fa-chevron-circle-down": u'\uf13a',
"fa-chevron-circle-left": u'\uf137',
"fa-chevron-circle-right": u'\uf138',
"fa-chevron-circle-up": u'\uf139',
"fa-chevron-down": u'\uf078',
"fa-chevron-left": u'\uf053',
"fa-chevron-right": u'\uf054',
"fa-chevron-up": u'\uf077',
"fa-child": u'\uf1ae',
"fa-chrome": u'\uf268',
"fa-circle": u'\uf111',
"fa-circle-o": u'\uf10c',
"fa-circle-o-notch": u'\uf1ce',
"fa-circle-thin": u'\uf1db',
"fa-clipboard": u'\uf0ea',
"fa-clock-o": u'\uf017',
"fa-clone": u'\uf24d',
"fa-close": u'\uf00d',
"fa-cloud": u'\uf0c2',
"fa-cloud-download": u'\uf0ed',
"fa-cloud-upload": u'\uf0ee',
"fa-cny": u'\uf157',
"fa-code": u'\uf121',
"fa-code-fork": u'\uf126',
"fa-codepen": u'\uf1cb',
"fa-coffee": u'\uf0f4',
"fa-cog": u'\uf013',
"fa-cogs": u'\uf085',
"fa-columns": u'\uf0db',
"fa-comment": u'\uf075',
"fa-comment-o": u'\uf0e5',
"fa-commenting": u'\uf27a',
"fa-commenting-o": u'\uf27b',
"fa-comments": u'\uf086',
"fa-comments-o": u'\uf0e6',
"fa-compass": u'\uf14e',
"fa-compress": u'\uf066',
"fa-connectdevelop": u'\uf20e',
"fa-contao": u'\uf26d',
"fa-copy": u'\uf0c5',
"fa-copyright": u'\uf1f9',
"fa-creative-commons": u'\uf25e',
"fa-credit-card": u'\uf09d',
"fa-crop": u'\uf125',
"fa-crosshairs": u'\uf05b',
"fa-css3": u'\uf13c',
"fa-cube": u'\uf1b2',
"fa-cubes": u'\uf1b3',
"fa-cut": u'\uf0c4',
"fa-cutlery": u'\uf0f5',
"fa-dashboard": u'\uf0e4',
"fa-dashcube": u'\uf210',
"fa-database": u'\uf1c0',
"fa-dedent": u'\uf03b',
"fa-delicious": u'\uf1a5',
"fa-desktop": u'\uf108',
"fa-deviantart": u'\uf1bd',
"fa-diamond": u'\uf219',
"fa-digg": u'\uf1a6',
"fa-dollar": u'\uf155',
"fa-dot-circle-o": u'\uf192',
"fa-download": u'\uf019',
"fa-dribbble": u'\uf17d',
"fa-dropbox": u'\uf16b',
"fa-drupal": u'\uf1a9',
"fa-edit": u'\uf044',
"fa-eject": u'\uf052',
"fa-ellipsis-h": u'\uf141',
"fa-ellipsis-v": u'\uf142',
"fa-empire": u'\uf1d1',
"fa-envelope": u'\uf0e0',
"fa-envelope-o": u'\uf003',
"fa-envelope-square": u'\uf199',
"fa-eraser": u'\uf12d',
"fa-eur": u'\uf153',
"fa-euro": u'\uf153',
"fa-exchange": u'\uf0ec',
"fa-exclamation": u'\uf12a',
"fa-exclamation-circle": u'\uf06a',
"fa-exclamation-triangle": u'\uf071',
"fa-expand": u'\uf065',
"fa-expeditedssl": u'\uf23e',
"fa-external-link": u'\uf08e',
"fa-external-link-square": u'\uf14c',
"fa-eye": u'\uf06e',
"fa-eye-slash": u'\uf070',
"fa-eyedropper": u'\uf1fb',
"fa-facebook": u'\uf09a',
"fa-facebook-f": u'\uf09a',
"fa-facebook-official": u'\uf230',
"fa-facebook-square": u'\uf082',
"fa-fast-backward": u'\uf049',
"fa-fast-forward": u'\uf050',
"fa-fax": u'\uf1ac',
"fa-feed": u'\uf09e',
"fa-female": u'\uf182',
"fa-fighter-jet": u'\uf0fb',
"fa-file": u'\uf15b',
"fa-file-archive-o": u'\uf1c6',
"fa-file-audio-o": u'\uf1c7',
"fa-file-code-o": u'\uf1c9',
"fa-file-excel-o": u'\uf1c3',
"fa-file-image-o": u'\uf1c5',
"fa-file-movie-o": u'\uf1c8',
"fa-file-o": u'\uf016',
"fa-file-pdf-o": u'\uf1c1',
"fa-file-photo-o": u'\uf1c5',
"fa-file-picture-o": u'\uf1c5',
"fa-file-powerpoint-o": u'\uf1c4',
"fa-file-sound-o": u'\uf1c7',
"fa-file-text": u'\uf15c',
"fa-file-text-o": u'\uf0f6',
"fa-file-video-o": u'\uf1c8',
"fa-file-word-o": u'\uf1c2',
"fa-file-zip-o": u'\uf1c6',
"fa-files-o": u'\uf0c5',
"fa-film": u'\uf008',
"fa-filter": u'\uf0b0',
"fa-fire": u'\uf06d',
"fa-fire-extinguisher": u'\uf134',
"fa-firefox": u'\uf269',
"fa-flag": u'\uf024',
"fa-flag-checkered": u'\uf11e',
"fa-flag-o": u'\uf11d',
"fa-flash": u'\uf0e7',
"fa-flask": u'\uf0c3',
"fa-flickr": u'\uf16e',
"fa-floppy-o": u'\uf0c7',
"fa-folder": u'\uf07b',
"fa-folder-o": u'\uf114',
"fa-folder-open": u'\uf07c',
"fa-folder-open-o": u'\uf115',
"fa-font": u'\uf031',
"fa-fonticons": u'\uf280',
"fa-forumbee": u'\uf211',
"fa-forward": u'\uf04e',
"fa-foursquare": u'\uf180',
"fa-frown-o": u'\uf119',
"fa-futbol-o": u'\uf1e3',
"fa-gamepad": u'\uf11b',
"fa-gavel": u'\uf0e3',
"fa-gbp": u'\uf154',
"fa-ge": u'\uf1d1',
"fa-gear": u'\uf013',
"fa-gears": u'\uf085',
"fa-genderless": u'\uf22d',
"fa-get-pocket": u'\uf265',
"fa-gg": u'\uf260',
"fa-gg-circle": u'\uf261',
"fa-gift": u'\uf06b',
"fa-git": u'\uf1d3',
"fa-git-square": u'\uf1d2',
"fa-github": u'\uf09b',
"fa-github-alt": u'\uf113',
"fa-github-square": u'\uf092',
"fa-gittip": u'\uf184',
"fa-glass": u'\uf000',
"fa-globe": u'\uf0ac',
"fa-google": u'\uf1a0',
"fa-google-plus": u'\uf0d5',
"fa-google-plus-square": u'\uf0d4',
"fa-google-wallet": u'\uf1ee',
"fa-graduation-cap": u'\uf19d',
"fa-gratipay": u'\uf184',
"fa-group": u'\uf0c0',
"fa-h-square": u'\uf0fd',
"fa-hacker-news": u'\uf1d4',
"fa-hand-grab-o": u'\uf255',
"fa-hand-lizard-o": u'\uf258',
"fa-hand-o-down": u'\uf0a7',
"fa-hand-o-left": u'\uf0a5',
"fa-hand-o-right": u'\uf0a4',
"fa-hand-o-up": u'\uf0a6',
"fa-hand-paper-o": u'\uf256',
"fa-hand-peace-o": u'\uf25b',
"fa-hand-pointer-o": u'\uf25a',
"fa-hand-rock-o": u'\uf255',
"fa-hand-scissors-o": u'\uf257',
"fa-hand-spock-o": u'\uf259',
"fa-hand-stop-o": u'\uf256',
"fa-hdd-o": u'\uf0a0',
"fa-header": u'\uf1dc',
"fa-headphones": u'\uf025',
"fa-heart": u'\uf004',
"fa-heart-o": u'\uf08a',
"fa-heartbeat": u'\uf21e',
"fa-history": u'\uf1da',
"fa-home": u'\uf015',
"fa-hospital-o": u'\uf0f8',
"fa-hotel": u'\uf236',
"fa-hourglass": u'\uf254',
"fa-hourglass-1": u'\uf251',
"fa-hourglass-2": u'\uf252',
"fa-hourglass-3": u'\uf253',
"fa-hourglass-end": u'\uf253',
"fa-hourglass-half": u'\uf252',
"fa-hourglass-o": u'\uf250',
"fa-hourglass-start": u'\uf251',
"fa-houzz": u'\uf27c',
"fa-html5": u'\uf13b',
"fa-i-cursor": u'\uf246',
"fa-ils": u'\uf20b',
"fa-image": u'\uf03e',
"fa-inbox": u'\uf01c',
"fa-indent": u'\uf03c',
"fa-industry": u'\uf275',
"fa-info": u'\uf129',
"fa-info-circle": u'\uf05a',
"fa-inr": u'\uf156',
"fa-instagram": u'\uf16d',
"fa-institution": u'\uf19c',
"fa-internet-explorer": u'\uf26b',
"fa-intersex": u'\uf224',
"fa-ioxhost": u'\uf208',
"fa-italic": u'\uf033',
"fa-joomla": u'\uf1aa',
"fa-jpy": u'\uf157',
"fa-jsfiddle": u'\uf1cc',
"fa-key": u'\uf084',
"fa-keyboard-o": u'\uf11c',
"fa-krw": u'\uf159',
"fa-language": u'\uf1ab',
"fa-laptop": u'\uf109',
"fa-lastfm": u'\uf202',
"fa-lastfm-square": u'\uf203',
"fa-leaf": u'\uf06c',
"fa-leanpub": u'\uf212',
"fa-legal": u'\uf0e3',
"fa-lemon-o": u'\uf094',
"fa-level-down": u'\uf149',
"fa-level-up": u'\uf148',
"fa-life-bouy": u'\uf1cd',
"fa-life-buoy": u'\uf1cd',
"fa-life-ring": u'\uf1cd',
"fa-life-saver": u'\uf1cd',
"fa-lightbulb-o": u'\uf0eb',
"fa-line-chart": u'\uf201',
"fa-link": u'\uf0c1',
"fa-linkedin": u'\uf0e1',
"fa-linkedin-square": u'\uf08c',
"fa-linux": u'\uf17c',
"fa-list": u'\uf03a',
"fa-list-alt": u'\uf022',
"fa-list-ol": u'\uf0cb',
"fa-list-ul": u'\uf0ca',
"fa-location-arrow": u'\uf124',
"fa-lock": u'\uf023',
"fa-long-arrow-down": u'\uf175',
"fa-long-arrow-left": u'\uf177',
"fa-long-arrow-right": u'\uf178',
"fa-long-arrow-up": u'\uf176',
"fa-magic": u'\uf0d0',
"fa-magnet": u'\uf076',
"fa-mail-forward": u'\uf064',
"fa-mail-reply": u'\uf112',
"fa-mail-reply-all": u'\uf122',
"fa-male": u'\uf183',
"fa-map": u'\uf279',
"fa-map-marker": u'\uf041',
"fa-map-o": u'\uf278',
"fa-map-pin": u'\uf276',
"fa-map-signs": u'\uf277',
"fa-mars": u'\uf222',
"fa-mars-double": u'\uf227',
"fa-mars-stroke": u'\uf229',
"fa-mars-stroke-h": u'\uf22b',
"fa-mars-stroke-v": u'\uf22a',
"fa-maxcdn": u'\uf136',
"fa-meanpath": u'\uf20c',
"fa-medium": u'\uf23a',
"fa-medkit": u'\uf0fa',
"fa-meh-o": u'\uf11a',
"fa-mercury": u'\uf223',
"fa-microphone": u'\uf130',
"fa-microphone-slash": u'\uf131',
"fa-minus": u'\uf068',
"fa-minus-circle": u'\uf056',
"fa-minus-square": u'\uf146',
"fa-minus-square-o": u'\uf147',
"fa-mobile": u'\uf10b',
"fa-mobile-phone": u'\uf10b',
"fa-money": u'\uf0d6',
"fa-moon-o": u'\uf186',
"fa-mortar-board": u'\uf19d',
"fa-motorcycle": u'\uf21c',
"fa-mouse-pointer": u'\uf245',
"fa-music": u'\uf001',
"fa-navicon": u'\uf0c9',
"fa-neuter": u'\uf22c',
"fa-newspaper-o": u'\uf1ea',
"fa-object-group": u'\uf247',
"fa-object-ungroup": u'\uf248',
"fa-odnoklassniki": u'\uf263',
"fa-odnoklassniki-square": u'\uf264',
"fa-opencart": u'\uf23d',
"fa-openid": u'\uf19b',
"fa-opera": u'\uf26a',
"fa-optin-monster": u'\uf23c',
"fa-outdent": u'\uf03b',
"fa-pagelines": u'\uf18c',
"fa-paint-brush": u'\uf1fc',
"fa-paper-plane": u'\uf1d8',
"fa-paper-plane-o": u'\uf1d9',
"fa-paperclip": u'\uf0c6',
"fa-paragraph": u'\uf1dd',
"fa-paste": u'\uf0ea',
"fa-pause": u'\uf04c',
"fa-paw": u'\uf1b0',
"fa-paypal": u'\uf1ed',
"fa-pencil": u'\uf040',
"fa-pencil-square": u'\uf14b',
"fa-pencil-square-o": u'\uf044',
"fa-phone": u'\uf095',
"fa-phone-square": u'\uf098',
"fa-photo": u'\uf03e',
"fa-picture-o": u'\uf03e',
"fa-pie-chart": u'\uf200',
"fa-pied-piper": u'\uf1a7',
"fa-pied-piper-alt": u'\uf1a8',
"fa-pinterest": u'\uf0d2',
"fa-pinterest-p": u'\uf231',
"fa-pinterest-square": u'\uf0d3',
"fa-plane": u'\uf072',
"fa-play": u'\uf04b',
"fa-play-circle": u'\uf144',
"fa-play-circle-o": u'\uf01d',
"fa-plug": u'\uf1e6',
"fa-plus": u'\uf067',
"fa-plus-circle": u'\uf055',
"fa-plus-square": u'\uf0fe',
"fa-plus-square-o": u'\uf196',
"fa-power-off": u'\uf011',
"fa-print": u'\uf02f',
"fa-puzzle-piece": u'\uf12e',
"fa-qq": u'\uf1d6',
"fa-qrcode": u'\uf029',
"fa-question": u'\uf128',
"fa-question-circle": u'\uf059',
"fa-quote-left": u'\uf10d',
"fa-quote-right": u'\uf10e',
"fa-ra": u'\uf1d0',
"fa-random": u'\uf074',
"fa-rebel": u'\uf1d0',
"fa-recycle": u'\uf1b8',
"fa-reddit": u'\uf1a1',
"fa-reddit-square": u'\uf1a2',
"fa-refresh": u'\uf021',
"fa-registered": u'\uf25d',
"fa-remove": u'\uf00d',
"fa-renren": u'\uf18b',
"fa-reorder": u'\uf0c9',
"fa-repeat": u'\uf01e',
"fa-reply": u'\uf112',
"fa-reply-all": u'\uf122',
"fa-retweet": u'\uf079',
"fa-rmb": u'\uf157',
"fa-road": u'\uf018',
"fa-rocket": u'\uf135',
"fa-rotate-left": u'\uf0e2',
"fa-rotate-right": u'\uf01e',
"fa-rouble": u'\uf158',
"fa-rss": u'\uf09e',
"fa-rss-square": u'\uf143',
"fa-rub": u'\uf158',
"fa-ruble": u'\uf158',
"fa-rupee": u'\uf156',
"fa-safari": u'\uf267',
"fa-save": u'\uf0c7',
"fa-scissors": u'\uf0c4',
"fa-search": u'\uf002',
"fa-search-minus": u'\uf010',
"fa-search-plus": u'\uf00e',
"fa-sellsy": u'\uf213',
"fa-send": u'\uf1d8',
"fa-send-o": u'\uf1d9',
"fa-server": u'\uf233',
"fa-share": u'\uf064',
"fa-share-alt": u'\uf1e0',
"fa-share-alt-square": u'\uf1e1',
"fa-share-square": u'\uf14d',
"fa-share-square-o": u'\uf045',
"fa-shekel": u'\uf20b',
"fa-sheqel": u'\uf20b',
"fa-shield": u'\uf132',
"fa-ship": u'\uf21a',
"fa-shirtsinbulk": u'\uf214',
"fa-shopping-cart": u'\uf07a',
"fa-sign-in": u'\uf090',
"fa-sign-out": u'\uf08b',
"fa-signal": u'\uf012',
"fa-simplybuilt": u'\uf215',
"fa-sitemap": u'\uf0e8',
"fa-skyatlas": u'\uf216',
"fa-skype": u'\uf17e',
"fa-slack": u'\uf198',
"fa-sliders": u'\uf1de',
"fa-slideshare": u'\uf1e7',
"fa-smile-o": u'\uf118',
"fa-soccer-ball-o": u'\uf1e3',
"fa-sort": u'\uf0dc',
"fa-sort-alpha-asc": u'\uf15d',
"fa-sort-alpha-desc": u'\uf15e',
"fa-sort-amount-asc": u'\uf160',
"fa-sort-amount-desc": u'\uf161',
"fa-sort-asc": u'\uf0de',
"fa-sort-desc": u'\uf0dd',
"fa-sort-down": u'\uf0dd',
"fa-sort-numeric-asc": u'\uf162',
"fa-sort-numeric-desc": u'\uf163',
"fa-sort-up": u'\uf0de',
"fa-soundcloud": u'\uf1be',
"fa-space-shuttle": u'\uf197',
"fa-spinner": u'\uf110',
"fa-spoon": u'\uf1b1',
"fa-spotify": u'\uf1bc',
"fa-square": u'\uf0c8',
"fa-square-o": u'\uf096',
"fa-stack-exchange": u'\uf18d',
"fa-stack-overflow": u'\uf16c',
"fa-star": u'\uf005',
"fa-star-half": u'\uf089',
"fa-star-half-empty": u'\uf123',
"fa-star-half-full": u'\uf123',
"fa-star-half-o": u'\uf123',
"fa-star-o": u'\uf006',
"fa-steam": u'\uf1b6',
"fa-steam-square": u'\uf1b7',
"fa-step-backward": u'\uf048',
"fa-step-forward": u'\uf051',
"fa-stethoscope": u'\uf0f1',
"fa-sticky-note": u'\uf249',
"fa-sticky-note-o": u'\uf24a',
"fa-stop": u'\uf04d',
"fa-street-view": u'\uf21d',
"fa-strikethrough": u'\uf0cc',
"fa-stumbleupon": u'\uf1a4',
"fa-stumbleupon-circle": u'\uf1a3',
"fa-subscript": u'\uf12c',
"fa-subway": u'\uf239',
"fa-suitcase": u'\uf0f2',
"fa-sun-o": u'\uf185',
"fa-superscript": u'\uf12b',
"fa-support": u'\uf1cd',
"fa-table": u'\uf0ce',
"fa-tablet": u'\uf10a',
"fa-tachometer": u'\uf0e4',
"fa-tag": u'\uf02b',
"fa-tags": u'\uf02c',
"fa-tasks": u'\uf0ae',
"fa-taxi": u'\uf1ba',
"fa-television": u'\uf26c',
"fa-tencent-weibo": u'\uf1d5',
"fa-terminal": u'\uf120',
"fa-text-height": u'\uf034',
"fa-text-width": u'\uf035',
"fa-th": u'\uf00a',
"fa-th-large": u'\uf009',
"fa-th-list": u'\uf00b',
"fa-thumb-tack": u'\uf08d',
"fa-thumbs-down": u'\uf165',
"fa-thumbs-o-down": u'\uf088',
"fa-thumbs-o-up": u'\uf087',
"fa-thumbs-up": u'\uf164',
"fa-ticket": u'\uf145',
"fa-times": u'\uf00d',
"fa-times-circle": u'\uf057',
"fa-times-circle-o": u'\uf05c',
"fa-tint": u'\uf043',
"fa-toggle-down": u'\uf150',
"fa-toggle-left": u'\uf191',
"fa-toggle-off": u'\uf204',
"fa-toggle-on": u'\uf205',
"fa-toggle-right": u'\uf152',
"fa-toggle-up": u'\uf151',
"fa-trademark": u'\uf25c',
"fa-train": u'\uf238',
"fa-transgender": u'\uf224',
"fa-transgender-alt": u'\uf225',
"fa-trash": u'\uf1f8',
"fa-trash-o": u'\uf014',
"fa-tree": u'\uf1bb',
"fa-trello": u'\uf181',
"fa-tripadvisor": u'\uf262',
"fa-trophy": u'\uf091',
"fa-truck": u'\uf0d1',
"fa-try": u'\uf195',
"fa-tty": u'\uf1e4',
"fa-tumblr": u'\uf173',
"fa-tumblr-square": u'\uf174',
"fa-turkish-lira": u'\uf195',
"fa-tv": u'\uf26c',
"fa-twitch": u'\uf1e8',
"fa-twitter": u'\uf099',
"fa-twitter-square": u'\uf081',
"fa-umbrella": u'\uf0e9',
"fa-underline": u'\uf0cd',
"fa-undo": u'\uf0e2',
"fa-university": u'\uf19c',
"fa-unlink": u'\uf127',
"fa-unlock": u'\uf09c',
"fa-unlock-alt": u'\uf13e',
"fa-unsorted": u'\uf0dc',
"fa-upload": u'\uf093',
"fa-usd": u'\uf155',
"fa-user": u'\uf007',
"fa-user-md": u'\uf0f0',
"fa-user-plus": u'\uf234',
"fa-user-secret": u'\uf21b',
"fa-user-times": u'\uf235',
"fa-users": u'\uf0c0',
"fa-venus": u'\uf221',
"fa-venus-double": u'\uf226',
"fa-venus-mars": u'\uf228',
"fa-viacoin": u'\uf237',
"fa-video-camera": u'\uf03d',
"fa-vimeo": u'\uf27d',
"fa-vimeo-square": u'\uf194',
"fa-vine": u'\uf1ca',
"fa-vk": u'\uf189',
"fa-volume-down": u'\uf027',
"fa-volume-off": u'\uf026',
"fa-volume-up": u'\uf028',
"fa-warning": u'\uf071',
"fa-wechat": u'\uf1d7',
"fa-weibo": u'\uf18a',
"fa-weixin": u'\uf1d7',
"fa-whatsapp": u'\uf232',
"fa-wheelchair": u'\uf193',
"fa-wifi": u'\uf1eb',
"fa-wikipedia-w": u'\uf266',
"fa-windows": u'\uf17a',
"fa-won": u'\uf159',
"fa-wordpress": u'\uf19a',
"fa-wrench": u'\uf0ad',
"fa-xing": u'\uf168',
"fa-xing-square": u'\uf169',
"fa-y-combinator": u'\uf23b'
}
Font awesome example
Don't forget the UTF-8 file declaration at the beginning or it will not work.
#!/usr/bin/python2
# -*- coding: utf-8 -*-
from ssd1306_2 import SSD1306_Display
from PIL import Image, ImageDraw, ImageFont
import fontawesome
dis = SSD1306_Display(0)
dis.initDisplay()
fa = fontawesome.font_awesome
font = ImageFont.truetype('./fontawesome.ttf', 60)
# Display all icons
for icon in fa.itervalues():
i = Image.new("1", (128,64))
d = ImageDraw.Draw(i, mode="1")
d.text((2,2), icon, fill=1, font=font)
dis.writeBuffer(dis.img2buffer(i.getdata()))
dis.displayBuffer()
del i
del d
Wrong number of line I noticed that both OLED displays that I own have only 62 rows of pixels instead of 64. I wonder if its a configuration error of if its the screen itself. It's very difficult to look at each individual pixel. I try to modify the configuration, but so far I have only be able to move the frame up/down by changing the starting line (0x40) to see the 63rd and 64th rows but it hides the 1st and second rows.