diff --git a/Adafruit_SSD1306/SSD1306.py b/Adafruit_SSD1306/SSD1306.py index cdb2821..f4ee132 100644 --- a/Adafruit_SSD1306/SSD1306.py +++ b/Adafruit_SSD1306/SSD1306.py @@ -18,6 +18,7 @@ # 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. +from __future__ import division import logging import time @@ -26,7 +27,7 @@ import Adafruit_GPIO.SPI as SPI # Constants -SSD1306_I2C_ADDRESS = 0x3C # 011110+SA0+RW - 0x3C or 0x3D +SSD1306_I2C_ADDRESS = 0x3C # 011110+SA0+RW - 0x3C or 0x3D SSD1306_SETCONTRAST = 0x81 SSD1306_DISPLAYALLON_RESUME = 0xA4 SSD1306_DISPLAYALLON = 0xA5 @@ -64,296 +65,296 @@ SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A class SSD1306Base(object): - """Base class for SSD1306-based OLED displays. Implementors should subclass - and provide an implementation for the _initialize function. - """ + """Base class for SSD1306-based OLED displays. Implementors should subclass + and provide an implementation for the _initialize function. + """ - def __init__(self, width, height, rst, dc=None, sclk=None, din=None, cs=None, - gpio=None, spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, - i2c=None): - self._log = logging.getLogger('Adafruit_SSD1306.SSD1306Base') - self._spi = None - self._i2c = None - self.width = width - self.height = height - self._pages = height/8 - self._buffer = [0]*(width*self._pages) - # Default to platform GPIO if not provided. - self._gpio = gpio - if self._gpio is None: - self._gpio = GPIO.get_platform_gpio() - # Setup reset pin. - self._rst = rst - self._gpio.setup(self._rst, GPIO.OUT) - # Handle hardware SPI - if spi is not None: - self._log.debug('Using hardware SPI') - self._spi = spi - self._spi.set_clock_hz(8000000) - # Handle software SPI - elif sclk is not None and din is not None and cs is not None: - self._log.debug('Using software SPI') - self._spi = SPI.BitBang(self._gpio, sclk, din, None, cs) - # Handle hardware I2C - elif i2c is not None: - self._log.debug('Using hardware I2C with custom I2C provider.') - self._i2c = i2c.get_i2c_device(i2c_address) - else: - self._log.debug('Using hardware I2C with platform I2C provider.') - import Adafruit_GPIO.I2C as I2C - if i2c_bus is None: - self._i2c = I2C.get_i2c_device(i2c_address) - else: - self._i2c = I2C.get_i2c_device(i2c_address, busnum=i2c_bus) - # Initialize DC pin if using SPI. - if self._spi is not None: - if dc is None: - raise ValueError('DC pin must be provided when using SPI.') - self._dc = dc - self._gpio.setup(self._dc, GPIO.OUT) - - def _initialize(self): - raise NotImplementedError + def __init__(self, width, height, rst, dc=None, sclk=None, din=None, cs=None, + gpio=None, spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, + i2c=None): + self._log = logging.getLogger('Adafruit_SSD1306.SSD1306Base') + self._spi = None + self._i2c = None + self.width = width + self.height = height + self._pages = height//8 + self._buffer = [0]*(width*self._pages) + # Default to platform GPIO if not provided. + self._gpio = gpio + if self._gpio is None: + self._gpio = GPIO.get_platform_gpio() + # Setup reset pin. + self._rst = rst + self._gpio.setup(self._rst, GPIO.OUT) + # Handle hardware SPI + if spi is not None: + self._log.debug('Using hardware SPI') + self._spi = spi + self._spi.set_clock_hz(8000000) + # Handle software SPI + elif sclk is not None and din is not None and cs is not None: + self._log.debug('Using software SPI') + self._spi = SPI.BitBang(self._gpio, sclk, din, None, cs) + # Handle hardware I2C + elif i2c is not None: + self._log.debug('Using hardware I2C with custom I2C provider.') + self._i2c = i2c.get_i2c_device(i2c_address) + else: + self._log.debug('Using hardware I2C with platform I2C provider.') + import Adafruit_GPIO.I2C as I2C + if i2c_bus is None: + self._i2c = I2C.get_i2c_device(i2c_address) + else: + self._i2c = I2C.get_i2c_device(i2c_address, busnum=i2c_bus) + # Initialize DC pin if using SPI. + if self._spi is not None: + if dc is None: + raise ValueError('DC pin must be provided when using SPI.') + self._dc = dc + self._gpio.setup(self._dc, GPIO.OUT) - def command(self, c): - """Send command byte to display.""" - if self._spi is not None: - # SPI write. - self._gpio.set_low(self._dc) - self._spi.write([c]) - else: - # I2C write. - control = 0x00 # Co = 0, DC = 0 - self._i2c.write8(control, c) + def _initialize(self): + raise NotImplementedError - def data(self, c): - """Send byte of data to display.""" - if self._spi is not None: - # SPI write. - self._gpio.set_high(self._dc) - self._spi.write([c]) - else: - # I2C write. - control = 0x40 # Co = 0, DC = 0 - self._i2c.write8(control, c) + def command(self, c): + """Send command byte to display.""" + if self._spi is not None: + # SPI write. + self._gpio.set_low(self._dc) + self._spi.write([c]) + else: + # I2C write. + control = 0x00 # Co = 0, DC = 0 + self._i2c.write8(control, c) - def begin(self, vccstate=SSD1306_SWITCHCAPVCC): - """Initialize display.""" - # Save vcc state. - self._vccstate = vccstate - # Reset and initialize display. - self.reset() - self._initialize() - # Turn on the display. - self.command(SSD1306_DISPLAYON) + def data(self, c): + """Send byte of data to display.""" + if self._spi is not None: + # SPI write. + self._gpio.set_high(self._dc) + self._spi.write([c]) + else: + # I2C write. + control = 0x40 # Co = 0, DC = 0 + self._i2c.write8(control, c) - def reset(self): - """Reset the display.""" - # Set reset high for a millisecond. - self._gpio.set_high(self._rst) - time.sleep(0.001) - # Set reset low for 10 milliseconds. - self._gpio.set_low(self._rst) - time.sleep(0.010) - # Set reset high again. - self._gpio.set_high(self._rst) + def begin(self, vccstate=SSD1306_SWITCHCAPVCC): + """Initialize display.""" + # Save vcc state. + self._vccstate = vccstate + # Reset and initialize display. + self.reset() + self._initialize() + # Turn on the display. + self.command(SSD1306_DISPLAYON) - def display(self): - """Write display buffer to physical display.""" - self.command(SSD1306_COLUMNADDR) - self.command(0) # Column start address. (0 = reset) - self.command(self.width-1) # Column end address. - self.command(SSD1306_PAGEADDR) - self.command(0) # Page start address. (0 = reset) - self.command(self._pages-1) # Page end address. - # Write buffer data. - if self._spi is not None: - # Set DC high for data. - self._gpio.set_high(self._dc) - # Write buffer. - self._spi.write(self._buffer) - else: - for i in range(0, len(self._buffer), 16): - control = 0x40 # Co = 0, DC = 0 - self._i2c.writeList(control, self._buffer[i:i+16]) + def reset(self): + """Reset the display.""" + # Set reset high for a millisecond. + self._gpio.set_high(self._rst) + time.sleep(0.001) + # Set reset low for 10 milliseconds. + self._gpio.set_low(self._rst) + time.sleep(0.010) + # Set reset high again. + self._gpio.set_high(self._rst) - def image(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. - """ - if image.mode != '1': - raise ValueError('Image must be in mode 1.') - imwidth, imheight = image.size - if imwidth != self.width or imheight != self.height: - raise ValueError('Image must be same dimensions as display ({0}x{1}).' \ - .format(self.width, self.height)) - # Grab all the pixels from the image, faster than getpixel. - pix = image.load() - # Iterate through the memory pages - index = 0 - for page in range(self._pages): - # Iterate through all x axis columns. - for x in range(self.width): - # Set the bits for the column of pixels at the current position. - bits = 0 - # Don't use range here as it's a bit slow - for bit in [0, 1, 2, 3, 4, 5, 6, 7]: - bits = bits << 1 - bits |= 0 if pix[(x, page*8+7-bit)] == 0 else 1 - # Update buffer byte and increment to next byte. - self._buffer[index] = bits - index += 1 + def display(self): + """Write display buffer to physical display.""" + self.command(SSD1306_COLUMNADDR) + self.command(0) # Column start address. (0 = reset) + self.command(self.width-1) # Column end address. + self.command(SSD1306_PAGEADDR) + self.command(0) # Page start address. (0 = reset) + self.command(self._pages-1) # Page end address. + # Write buffer data. + if self._spi is not None: + # Set DC high for data. + self._gpio.set_high(self._dc) + # Write buffer. + self._spi.write(self._buffer) + else: + for i in range(0, len(self._buffer), 16): + control = 0x40 # Co = 0, DC = 0 + self._i2c.writeList(control, self._buffer[i:i+16]) - def clear(self): - """Clear contents of image buffer.""" - self._buffer = [0]*(self.width*self._pages) + def image(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. + """ + if image.mode != '1': + raise ValueError('Image must be in mode 1.') + imwidth, imheight = image.size + if imwidth != self.width or imheight != self.height: + raise ValueError('Image must be same dimensions as display ({0}x{1}).' \ + .format(self.width, self.height)) + # Grab all the pixels from the image, faster than getpixel. + pix = image.load() + # Iterate through the memory pages + index = 0 + for page in range(self._pages): + # Iterate through all x axis columns. + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + bits = 0 + # Don't use range here as it's a bit slow + for bit in [0, 1, 2, 3, 4, 5, 6, 7]: + bits = bits << 1 + bits |= 0 if pix[(x, page*8+7-bit)] == 0 else 1 + # Update buffer byte and increment to next byte. + self._buffer[index] = bits + index += 1 - def set_contrast(self, contrast): - """Sets the contrast of the display. Contrast should be a value between - 0 and 255.""" - if contrast < 0 or contrast > 255: - raise ValueError('Contrast must be a value from 0 to 255 (inclusive).') - self.command(SSD1306_SETCONTRAST) - self.command(contrast) + def clear(self): + """Clear contents of image buffer.""" + self._buffer = [0]*(self.width*self._pages) - def dim(self, dim): - """Adjusts contrast to dim the display if dim is True, otherwise sets the - contrast to normal brightness if dim is False. - """ - # Assume dim display. - contrast = 0 - # Adjust contrast based on VCC if not dimming. - if not dim: - if self._vccstate == SSD1306_EXTERNALVCC: - contrast = 0x9F - else: - contrast = 0xCF + def set_contrast(self, contrast): + """Sets the contrast of the display. Contrast should be a value between + 0 and 255.""" + if contrast < 0 or contrast > 255: + raise ValueError('Contrast must be a value from 0 to 255 (inclusive).') + self.command(SSD1306_SETCONTRAST) + self.command(contrast) + + def dim(self, dim): + """Adjusts contrast to dim the display if dim is True, otherwise sets the + contrast to normal brightness if dim is False. + """ + # Assume dim display. + contrast = 0 + # Adjust contrast based on VCC if not dimming. + if not dim: + if self._vccstate == SSD1306_EXTERNALVCC: + contrast = 0x9F + else: + contrast = 0xCF class SSD1306_128_64(SSD1306Base): - def __init__(self, rst, dc=None, sclk=None, din=None, cs=None, gpio=None, - spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, - i2c=None): - # Call base class constructor. - super(SSD1306_128_64, self).__init__(128, 64, rst, dc, sclk, din, cs, - gpio, spi, i2c_bus, i2c_address, i2c) + def __init__(self, rst, dc=None, sclk=None, din=None, cs=None, gpio=None, + spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, + i2c=None): + # Call base class constructor. + super(SSD1306_128_64, self).__init__(128, 64, rst, dc, sclk, din, cs, + gpio, spi, i2c_bus, i2c_address, i2c) - def _initialize(self): - # 128x64 pixel specific initialization. - self.command(SSD1306_DISPLAYOFF) # 0xAE - self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5 - self.command(0x80) # the suggested ratio 0x80 - self.command(SSD1306_SETMULTIPLEX) # 0xA8 - self.command(0x3F) - self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3 - self.command(0x0) # no offset - self.command(SSD1306_SETSTARTLINE | 0x0) # line #0 - self.command(SSD1306_CHARGEPUMP) # 0x8D - if self._vccstate == SSD1306_EXTERNALVCC: - self.command(0x10) - else: - self.command(0x14) - self.command(SSD1306_MEMORYMODE) # 0x20 - self.command(0x00) # 0x0 act like ks0108 - self.command(SSD1306_SEGREMAP | 0x1) - self.command(SSD1306_COMSCANDEC) - self.command(SSD1306_SETCOMPINS) # 0xDA - self.command(0x12) - self.command(SSD1306_SETCONTRAST) # 0x81 - if self._vccstate == SSD1306_EXTERNALVCC: - self.command(0x9F) - else: - self.command(0xCF) - self.command(SSD1306_SETPRECHARGE) # 0xd9 - if self._vccstate == SSD1306_EXTERNALVCC: - self.command(0x22) - else: - self.command(0xF1) - self.command(SSD1306_SETVCOMDETECT) # 0xDB - self.command(0x40) - self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4 - self.command(SSD1306_NORMALDISPLAY) # 0xA6 + def _initialize(self): + # 128x64 pixel specific initialization. + self.command(SSD1306_DISPLAYOFF) # 0xAE + self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5 + self.command(0x80) # the suggested ratio 0x80 + self.command(SSD1306_SETMULTIPLEX) # 0xA8 + self.command(0x3F) + self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3 + self.command(0x0) # no offset + self.command(SSD1306_SETSTARTLINE | 0x0) # line #0 + self.command(SSD1306_CHARGEPUMP) # 0x8D + if self._vccstate == SSD1306_EXTERNALVCC: + self.command(0x10) + else: + self.command(0x14) + self.command(SSD1306_MEMORYMODE) # 0x20 + self.command(0x00) # 0x0 act like ks0108 + self.command(SSD1306_SEGREMAP | 0x1) + self.command(SSD1306_COMSCANDEC) + self.command(SSD1306_SETCOMPINS) # 0xDA + self.command(0x12) + self.command(SSD1306_SETCONTRAST) # 0x81 + if self._vccstate == SSD1306_EXTERNALVCC: + self.command(0x9F) + else: + self.command(0xCF) + self.command(SSD1306_SETPRECHARGE) # 0xd9 + if self._vccstate == SSD1306_EXTERNALVCC: + self.command(0x22) + else: + self.command(0xF1) + self.command(SSD1306_SETVCOMDETECT) # 0xDB + self.command(0x40) + self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4 + self.command(SSD1306_NORMALDISPLAY) # 0xA6 class SSD1306_128_32(SSD1306Base): - def __init__(self, rst, dc=None, sclk=None, din=None, cs=None, gpio=None, - spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, - i2c=None): - # Call base class constructor. - super(SSD1306_128_32, self).__init__(128, 32, rst, dc, sclk, din, cs, - gpio, spi, i2c_bus, i2c_address, i2c) + def __init__(self, rst, dc=None, sclk=None, din=None, cs=None, gpio=None, + spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, + i2c=None): + # Call base class constructor. + super(SSD1306_128_32, self).__init__(128, 32, rst, dc, sclk, din, cs, + gpio, spi, i2c_bus, i2c_address, i2c) - def _initialize(self): - # 128x32 pixel specific initialization. - self.command(SSD1306_DISPLAYOFF) # 0xAE - self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5 - self.command(0x80) # the suggested ratio 0x80 - self.command(SSD1306_SETMULTIPLEX) # 0xA8 - self.command(0x1F) - self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3 - self.command(0x0) # no offset - self.command(SSD1306_SETSTARTLINE | 0x0) # line #0 - self.command(SSD1306_CHARGEPUMP) # 0x8D - if self._vccstate == SSD1306_EXTERNALVCC: - self.command(0x10) - else: - self.command(0x14) - self.command(SSD1306_MEMORYMODE) # 0x20 - self.command(0x00) # 0x0 act like ks0108 - self.command(SSD1306_SEGREMAP | 0x1) - self.command(SSD1306_COMSCANDEC) - self.command(SSD1306_SETCOMPINS) # 0xDA - self.command(0x02) - self.command(SSD1306_SETCONTRAST) # 0x81 - self.command(0x8F) - self.command(SSD1306_SETPRECHARGE) # 0xd9 - if self._vccstate == SSD1306_EXTERNALVCC: - self.command(0x22) - else: - self.command(0xF1) - self.command(SSD1306_SETVCOMDETECT) # 0xDB - self.command(0x40) - self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4 - self.command(SSD1306_NORMALDISPLAY) # 0xA6 + def _initialize(self): + # 128x32 pixel specific initialization. + self.command(SSD1306_DISPLAYOFF) # 0xAE + self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5 + self.command(0x80) # the suggested ratio 0x80 + self.command(SSD1306_SETMULTIPLEX) # 0xA8 + self.command(0x1F) + self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3 + self.command(0x0) # no offset + self.command(SSD1306_SETSTARTLINE | 0x0) # line #0 + self.command(SSD1306_CHARGEPUMP) # 0x8D + if self._vccstate == SSD1306_EXTERNALVCC: + self.command(0x10) + else: + self.command(0x14) + self.command(SSD1306_MEMORYMODE) # 0x20 + self.command(0x00) # 0x0 act like ks0108 + self.command(SSD1306_SEGREMAP | 0x1) + self.command(SSD1306_COMSCANDEC) + self.command(SSD1306_SETCOMPINS) # 0xDA + self.command(0x02) + self.command(SSD1306_SETCONTRAST) # 0x81 + self.command(0x8F) + self.command(SSD1306_SETPRECHARGE) # 0xd9 + if self._vccstate == SSD1306_EXTERNALVCC: + self.command(0x22) + else: + self.command(0xF1) + self.command(SSD1306_SETVCOMDETECT) # 0xDB + self.command(0x40) + self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4 + self.command(SSD1306_NORMALDISPLAY) # 0xA6 class SSD1306_96_16(SSD1306Base): - def __init__(self, rst, dc=None, sclk=None, din=None, cs=None, gpio=None, - spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, - i2c=None): - # Call base class constructor. - super(SSD1306_96_16, self).__init__(96, 16, rst, dc, sclk, din, cs, - gpio, spi, i2c_bus, i2c_address, i2c) + def __init__(self, rst, dc=None, sclk=None, din=None, cs=None, gpio=None, + spi=None, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS, + i2c=None): + # Call base class constructor. + super(SSD1306_96_16, self).__init__(96, 16, rst, dc, sclk, din, cs, + gpio, spi, i2c_bus, i2c_address, i2c) - def _initialize(self): - # 128x32 pixel specific initialization. - self.command(SSD1306_DISPLAYOFF) # 0xAE - self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5 - self.command(0x60) # the suggested ratio 0x60 - self.command(SSD1306_SETMULTIPLEX) # 0xA8 - self.command(0x0F) - self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3 - self.command(0x0) # no offset - self.command(SSD1306_SETSTARTLINE | 0x0) # line #0 - self.command(SSD1306_CHARGEPUMP) # 0x8D - if self._vccstate == SSD1306_EXTERNALVCC: - self.command(0x10) - else: - self.command(0x14) - self.command(SSD1306_MEMORYMODE) # 0x20 - self.command(0x00) # 0x0 act like ks0108 - self.command(SSD1306_SEGREMAP | 0x1) - self.command(SSD1306_COMSCANDEC) - self.command(SSD1306_SETCOMPINS) # 0xDA - self.command(0x02) - self.command(SSD1306_SETCONTRAST) # 0x81 - self.command(0x8F) - self.command(SSD1306_SETPRECHARGE) # 0xd9 - if self._vccstate == SSD1306_EXTERNALVCC: - self.command(0x22) - else: - self.command(0xF1) - self.command(SSD1306_SETVCOMDETECT) # 0xDB - self.command(0x40) - self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4 - self.command(SSD1306_NORMALDISPLAY) # 0xA6 + def _initialize(self): + # 128x32 pixel specific initialization. + self.command(SSD1306_DISPLAYOFF) # 0xAE + self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5 + self.command(0x60) # the suggested ratio 0x60 + self.command(SSD1306_SETMULTIPLEX) # 0xA8 + self.command(0x0F) + self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3 + self.command(0x0) # no offset + self.command(SSD1306_SETSTARTLINE | 0x0) # line #0 + self.command(SSD1306_CHARGEPUMP) # 0x8D + if self._vccstate == SSD1306_EXTERNALVCC: + self.command(0x10) + else: + self.command(0x14) + self.command(SSD1306_MEMORYMODE) # 0x20 + self.command(0x00) # 0x0 act like ks0108 + self.command(SSD1306_SEGREMAP | 0x1) + self.command(SSD1306_COMSCANDEC) + self.command(SSD1306_SETCOMPINS) # 0xDA + self.command(0x02) + self.command(SSD1306_SETCONTRAST) # 0x81 + self.command(0x8F) + self.command(SSD1306_SETPRECHARGE) # 0xd9 + if self._vccstate == SSD1306_EXTERNALVCC: + self.command(0x22) + else: + self.command(0xF1) + self.command(SSD1306_SETVCOMDETECT) # 0xDB + self.command(0x40) + self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4 + self.command(SSD1306_NORMALDISPLAY) # 0xA6 diff --git a/Adafruit_SSD1306/__init__.py b/Adafruit_SSD1306/__init__.py index b39f924..25a32a7 100644 --- a/Adafruit_SSD1306/__init__.py +++ b/Adafruit_SSD1306/__init__.py @@ -1 +1 @@ -from SSD1306 import * \ No newline at end of file +from .SSD1306 import * diff --git a/examples/animate.py b/examples/animate.py index d3f799b..5b3c95a 100644 --- a/examples/animate.py +++ b/examples/animate.py @@ -24,9 +24,9 @@ import time import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 -import Image -import ImageFont -import ImageDraw +from PIL import Image +from PIL import ImageFont +from PIL import ImageDraw # Raspberry Pi pin configuration: @@ -91,36 +91,36 @@ velocity = -2 startpos = width # Animate text moving in sine wave. -print 'Press Ctrl-C to quit.' +print('Press Ctrl-C to quit.') pos = startpos while True: - # Clear image buffer by drawing a black filled box. - draw.rectangle((0,0,width,height), outline=0, fill=0) - # Enumerate characters and draw them offset vertically based on a sine wave. - x = pos - for i, c in enumerate(text): - # Stop drawing if off the right side of screen. - if x > width: - break - # Calculate width but skip drawing if off the left side of screen. - if x < -10: - char_width, char_height = draw.textsize(c, font=font) - x += char_width - continue - # Calculate offset from sine wave. - y = offset+math.floor(amplitude*math.sin(x/float(width)*2.0*math.pi)) - # Draw text. - draw.text((x, y), c, font=font, fill=255) - # Increment x position based on chacacter width. - char_width, char_height = draw.textsize(c, font=font) - x += char_width - # Draw the image buffer. - disp.image(image) - disp.display() - # Move position for next frame. - pos += velocity - # Start over if text has scrolled completely off left side of screen. - if pos < -maxwidth: - pos = startpos - # Pause briefly before drawing next frame. - time.sleep(0.1) + # Clear image buffer by drawing a black filled box. + draw.rectangle((0,0,width,height), outline=0, fill=0) + # Enumerate characters and draw them offset vertically based on a sine wave. + x = pos + for i, c in enumerate(text): + # Stop drawing if off the right side of screen. + if x > width: + break + # Calculate width but skip drawing if off the left side of screen. + if x < -10: + char_width, char_height = draw.textsize(c, font=font) + x += char_width + continue + # Calculate offset from sine wave. + y = offset+math.floor(amplitude*math.sin(x/float(width)*2.0*math.pi)) + # Draw text. + draw.text((x, y), c, font=font, fill=255) + # Increment x position based on chacacter width. + char_width, char_height = draw.textsize(c, font=font) + x += char_width + # Draw the image buffer. + disp.image(image) + disp.display() + # Move position for next frame. + pos += velocity + # Start over if text has scrolled completely off left side of screen. + if pos < -maxwidth: + pos = startpos + # Pause briefly before drawing next frame. + time.sleep(0.1) diff --git a/examples/image.py b/examples/image.py index a0e2b1f..c3da587 100644 --- a/examples/image.py +++ b/examples/image.py @@ -23,7 +23,7 @@ import time import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 -import Image +from PIL import Image # Raspberry Pi pin configuration: @@ -61,9 +61,9 @@ disp.display() # Load image based on OLED display height. Note that image is converted to 1 bit color. if disp.height == 64: - image = Image.open('happycat_oled_64.ppm').convert('1') + image = Image.open('happycat_oled_64.ppm').convert('1') else: - image = Image.open('happycat_oled_32.ppm').convert('1') + image = Image.open('happycat_oled_32.ppm').convert('1') # Alternatively load a different format image, resize it, and convert to 1 bit color. #image = Image.open('happycat.png').resize((disp.width, disp.height), Image.ANTIALIAS).convert('1') diff --git a/examples/shapes.py b/examples/shapes.py index 45ee5ec..4c1cee2 100644 --- a/examples/shapes.py +++ b/examples/shapes.py @@ -23,9 +23,9 @@ import time import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 -import Image -import ImageDraw -import ImageFont +from PIL import Image +from PIL import ImageDraw +from PIL import ImageFont # Raspberry Pi pin configuration: diff --git a/setup.py b/setup.py index 061ec35..332d647 100644 --- a/setup.py +++ b/setup.py @@ -2,13 +2,23 @@ from ez_setup import use_setuptools use_setuptools() from setuptools import setup, find_packages -setup(name = 'Adafruit_SSD1306', - version = '1.5.0', - author = 'Tony DiCola', - author_email = 'tdicola@adafruit.com', - description = 'Python library to use SSD1306-based 128x64 or 128x32 pixel OLED displays with a Raspberry Pi or Beaglebone Black.', - license = 'MIT', - url = 'https://github.com/adafruit/Adafruit_Python_SSD1306/', - dependency_links = ['https://github.com/adafruit/Adafruit_Python_GPIO/tarball/master#egg=Adafruit-GPIO-0.6.5'], - install_requires = ['Adafruit-GPIO>=0.6.5'], - packages = find_packages()) +classifiers = ['Development Status :: 4 - Beta', + 'Operating System :: POSIX :: Linux', + 'License :: OSI Approved :: MIT License', + 'Intended Audience :: Developers', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development', + 'Topic :: System :: Hardware'] + +setup(name = 'Adafruit_SSD1306', + version = '1.6.0', + author = 'Tony DiCola', + author_email = 'tdicola@adafruit.com', + description = 'Python library to use SSD1306-based 128x64 or 128x32 pixel OLED displays with a Raspberry Pi or Beaglebone Black.', + license = 'MIT', + classifiers = classifiers, + url = 'https://github.com/adafruit/Adafruit_Python_SSD1306/', + dependency_links = ['https://github.com/adafruit/Adafruit_Python_GPIO/tarball/master#egg=Adafruit-GPIO-0.6.5'], + install_requires = ['Adafruit-GPIO>=0.6.5'], + packages = find_packages())