From 2fad2d932f1e40922ffe7e202a5854a3e8f86d09 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 26 Jul 2021 15:40:58 +0100 Subject: [PATCH 01/12] Fix set_image reshape for #93 --- library/inky/inky_uc8159.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/inky/inky_uc8159.py b/library/inky/inky_uc8159.py index 5b4ba2c0..604d1ec9 100644 --- a/library/inky/inky_uc8159.py +++ b/library/inky/inky_uc8159.py @@ -389,7 +389,7 @@ def set_image(self, image, saturation=0.5): # Force source image data to be loaded for `.im` to work image.load() image = image.im.convert("P", True, palette_image.im) - self.buf = numpy.array(image, dtype=numpy.uint8).reshape((self.cols, self.rows)) + self.buf = numpy.array(image, dtype=numpy.uint8).reshape((self.rows, self.cols)) def _spi_write(self, dc, values): """Write values over SPI. From e073c8e5d1bffa27f370c0c6ae1ecccabb62a366 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 27 Jul 2021 11:25:21 +0100 Subject: [PATCH 02/12] Update Sphinx deps --- sphinx/conf.py | 4 +++- sphinx/requirements.txt | 50 ++++++++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/sphinx/conf.py b/sphinx/conf.py index 09c9323b..630cae8a 100644 --- a/sphinx/conf.py +++ b/sphinx/conf.py @@ -24,6 +24,7 @@ from sphinx.ext import autodoc + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -37,6 +38,7 @@ 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx', + 'sphinx.ext.autosummary' ] autoclass_content = 'both' @@ -98,7 +100,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'sphinx.virtualenv'] # The reST default role (used for this markup: `text`) to use for all # documents. diff --git a/sphinx/requirements.txt b/sphinx/requirements.txt index c8cedd45..901071ba 100644 --- a/sphinx/requirements.txt +++ b/sphinx/requirements.txt @@ -1,23 +1,31 @@ alabaster==0.7.12 -Babel==2.6.0 -certifi==2019.3.9 -chardet==3.0.4 -docutils==0.14 +Babel==2.9.1 +certifi==2021.5.30 +chardet==4.0.0 +charset-normalizer==2.0.3 +docutils==0.16 funcsigs==1.0.2 -idna==2.8 -imagesize==1.1.0 -Jinja2==2.10.1 -MarkupSafe==1.1.1 -mock==3.0.5 -packaging==19.0 -Pygments==2.4.0 -pyparsing==2.4.0 -pytz==2019.1 -requests==2.22.0 -six==1.12.0 -snowballstemmer==1.2.1 -Sphinx==1.8.5 -sphinx-rtd-theme==0.4.3 -sphinxcontrib-websupport==1.1.2 -typing==3.6.6 -urllib3==1.25.3 +idna==3.2 +imagesize==1.2.0 +Jinja2==3.0.1 +MarkupSafe==2.0.1 +mock==4.0.3 +packaging==21.0 +Pillow==8.3.1 +Pygments==2.9.0 +pyparsing==2.4.7 +pytz==2021.1 +requests==2.26.0 +six==1.16.0 +snowballstemmer==2.1.0 +Sphinx==4.1.2 +sphinx-rtd-theme==0.5.2 +sphinxcontrib-applehelp==1.0.2 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==2.0.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-websupport==1.2.4 +typing==3.7.4.3 +urllib3==1.26.6 From f5495edc2e5ed0cc271c375c75e32c5983f71363 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 27 Jul 2021 11:53:07 +0100 Subject: [PATCH 03/12] Add mocking support to auto() Add the ability to mock WHAT, PHAT, PHATSSD1608 and Impression by supplying the `--simulate` command-line argument. Fix a bug with clean.py where it tried to parse the auto() args and bailed. --- examples/clean.py | 2 +- library/inky/auto.py | 37 +++++++++++++++++++++++++++++-------- library/inky/inky.py | 1 + library/inky/mock.py | 20 +++++++++++++++++++- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/examples/clean.py b/examples/clean.py index 4af84789..fe72680a 100755 --- a/examples/clean.py +++ b/examples/clean.py @@ -19,7 +19,7 @@ # Command line arguments to determine number of cycles to run parser = argparse.ArgumentParser() parser.add_argument('--number', '-n', type=int, required=False, help="number of cycles") -args = parser.parse_args() +args, _ = parser.parse_known_args() # The number of red / black / white refreshes to run diff --git a/library/inky/auto.py b/library/inky/auto.py index e157c2bb..475d2fcb 100644 --- a/library/inky/auto.py +++ b/library/inky/auto.py @@ -28,17 +28,38 @@ def auto(i2c_bus=None, ask_user=False, verbose=False): print("""Failed to detect an Inky board, you must specify the type and colour manually. """) parser = argparse.ArgumentParser() + parser.add_argument('--simulate', '-s', action='store_true', default=False, help="Simulate Inky display") parser.add_argument('--type', '-t', type=str, required=True, choices=["what", "phat", "phatssd1608", "impressions", "7colour"], help="Type of display") parser.add_argument('--colour', '-c', type=str, required=False, choices=["red", "black", "yellow"], help="Display colour") args, _ = parser.parse_known_args() - if args.type == "phat": - return InkyPHAT(args.colour) - if args.type == "phatssd1608": - return InkyPHAT_SSD1608(args.colour) - if args.type == "what": - return InkyWHAT(args.colour) - if args.type in ("impressions", "7colour"): - return InkyUC8159() + if args.simulate: + cls = None + if args.type == "phat": + from .mock import InkyMockPHAT + cls = InkyMockPHAT(args.colour) + if args.type == "phatssd1608": + from .mock import InkyMockPHATSSD1608 + cls = InkyMockPHATSSD1608(args.colour) + if args.type == "what": + from .mock import InkyMockWHAT + cls = InkyMockWHAT(args.colour) + if args.type in ("impressions", "7colour"): + from .mock import InkyMockImpression + cls = InkyMockImpression() + if cls is not None: + import atexit + atexit.register(cls.wait_for_window_close) + return cls + raise RuntimeError("Unable to simulate {}".format(args.type)) + else: + if args.type == "phat": + return InkyPHAT(args.colour) + if args.type == "phatssd1608": + return InkyPHAT_SSD1608(args.colour) + if args.type == "what": + return InkyWHAT(args.colour) + if args.type in ("impressions", "7colour"): + return InkyUC8159() if _eeprom is None: raise RuntimeError("No EEPROM detected! You must manually initialise your Inky board.") diff --git a/library/inky/inky.py b/library/inky/inky.py index eab05f9f..a1e5ddc0 100644 --- a/library/inky/inky.py +++ b/library/inky/inky.py @@ -36,6 +36,7 @@ (600, 448): (600, 448, 0), (400, 300): (400, 300, 0), (212, 104): (104, 212, -90), + (250, 122): (250, 122, -90), } diff --git a/library/inky/mock.py b/library/inky/mock.py index fdc8789b..1a381a44 100644 --- a/library/inky/mock.py +++ b/library/inky/mock.py @@ -149,7 +149,7 @@ def show(self, busy_wait=True): class InkyMockPHAT(InkyMock): - """Inky wHAT e-Ink Display Simulator.""" + """Inky PHAT (212x104) e-Ink Display Simulator.""" WIDTH = 212 HEIGHT = 104 @@ -166,6 +166,24 @@ def _simulate(self, region): self._display(region) +class InkyMockPHATSSD1608(InkyMock): + """Inky PHAT SSD1608 (250x122) e-Ink Display Simulator.""" + + WIDTH = 250 + HEIGHT = 122 + + WHITE = 0 + BLACK = 1 + RED = 2 + YELLOW = 2 + + def _simulate(self, region): + region = numpy.rot90(region, self.rotation // 90) + region = numpy.flipud(region) # spec: phat rotated -90 + region = numpy.fliplr(region) # spec: phat rotated -90 + self._display(region) + + class InkyMockWHAT(InkyMock): """Inky wHAT e-Ink Display Simulator.""" From 696fe0732933c18a1f57dd7db1014709264a61aa Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 27 Jul 2021 12:25:06 +0100 Subject: [PATCH 04/12] Try to make auto() error friendlier --- library/inky/auto.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/inky/auto.py b/library/inky/auto.py index 475d2fcb..17ba1b45 100644 --- a/library/inky/auto.py +++ b/library/inky/auto.py @@ -25,8 +25,7 @@ def auto(i2c_bus=None, ask_user=False, verbose=False): if ask_user: if verbose: - print("""Failed to detect an Inky board, you must specify the type and colour manually. -""") + print("Failed to detect an Inky board. Trying --type/--colour arguments instead...\n") parser = argparse.ArgumentParser() parser.add_argument('--simulate', '-s', action='store_true', default=False, help="Simulate Inky display") parser.add_argument('--type', '-t', type=str, required=True, choices=["what", "phat", "phatssd1608", "impressions", "7colour"], help="Type of display") From fc17026df35447c1147e9bfa38988e89e75c80e6 Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Fri, 15 Oct 2021 12:33:23 +0100 Subject: [PATCH 05/12] Add alternate palette for newer Inkys --- tools/inky-palette-alt.gpl | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tools/inky-palette-alt.gpl diff --git a/tools/inky-palette-alt.gpl b/tools/inky-palette-alt.gpl new file mode 100644 index 00000000..35f0a0ee --- /dev/null +++ b/tools/inky-palette-alt.gpl @@ -0,0 +1,7 @@ +GIMP Palette +Name: Inky pHAT - alt palette for newer Inkys +Columns: 1 +# +255 255 255 Untitled +255 0 0 Untitled + 0 0 0 Untitled From bc5db21796bee335e7d4a6373e82d0e55eda6c41 Mon Sep 17 00:00:00 2001 From: Philip Howard Date: Fri, 5 Nov 2021 13:55:12 +0000 Subject: [PATCH 06/12] UC8159: Support for 640x400 resolution panel Add 640x400 as a supported resolution and attempt to auto-detect resolution from the EEPROM. Add panel setting, which is required for the resolution change to work. --- library/inky/inky_uc8159.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/library/inky/inky_uc8159.py b/library/inky/inky_uc8159.py index 604d1ec9..f52d630f 100644 --- a/library/inky/inky_uc8159.py +++ b/library/inky/inky_uc8159.py @@ -87,7 +87,8 @@ _SPI_DATA = 1 _RESOLUTION = { - (600, 448): (600, 448, 0, 0, 0) + (600, 448): (600, 448, 0, 0, 0, 0b11), + (640, 400): (640, 400, 0, 0, 0, 0b10) } @@ -128,7 +129,7 @@ def __init__(self, resolution=(600, 448), colour='multi', cs_pin=CS0_PIN, dc_pin self.resolution = resolution self.width, self.height = resolution self.border_colour = WHITE - self.cols, self.rows, self.rotation, self.offset_x, self.offset_y = _RESOLUTION[resolution] + self.cols, self.rows, self.rotation, self.offset_x, self.offset_y, self.resolution_setting = _RESOLUTION[resolution] if colour not in ('multi'): raise ValueError('Colour {} is not supported!'.format(colour)) @@ -137,6 +138,14 @@ def __init__(self, resolution=(600, 448), colour='multi', cs_pin=CS0_PIN, dc_pin self.eeprom = eeprom.read_eeprom(i2c_bus=i2c_bus) self.lut = colour + # Get resolution from the EEPROM if it's valid + # Eg: 600x480 and 640x400 + eeprom_resolution = self.eeprom.width, self.eeprom.height + if eeprom_resolution in _RESOLUTION.keys(): + self.resolution = eeprom_resolution + self.width, self.height = eeprom_resolution + self.cols, self.rows, self.rotation, self.offset_x, self.offset_y, self.resolution_setting = _RESOLUTION[eeprom_resolution] + # The EEPROM is used to disambiguate the variants of wHAT and pHAT # 1 Red pHAT (High-Temp) # 2 Yellow wHAT (1_E) @@ -241,11 +250,13 @@ def setup(self): # 0b00000100 = Source shift direction, 0 = left, 1 = right (default) # 0b00000010 = DC-DC converter, 0 = off, 1 = on # 0b00000001 = Soft reset, 0 = Reset, 1 = Normal (Default) + # 0b11 = 600x448 + # 0b10 = 640x400 self._send_command( UC8159_PSR, [ - 0b11101111, # See above for more magic numbers - 0x08 # display_colours == UC8159_7C + (self.resolution_setting << 6) | 0b101111, # See above for more magic numbers + 0x08 # display_colours == UC8159_7C ] ) From 9fdec7949559f18b81cf0f5a53ee15316748ec77 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 25 Nov 2021 11:16:07 +0000 Subject: [PATCH 07/12] UC8159: Detect 640x400 as ID 15 --- library/inky/auto.py | 2 ++ library/inky/eeprom.py | 3 ++- library/inky/inky_uc8159.py | 27 +++------------------------ 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/library/inky/auto.py b/library/inky/auto.py index 17ba1b45..49cc17fc 100644 --- a/library/inky/auto.py +++ b/library/inky/auto.py @@ -22,6 +22,8 @@ def auto(i2c_bus=None, ask_user=False, verbose=False): return InkyWHAT(_eeprom.get_color()) if _eeprom.display_variant == 14: return InkyUC8159() + if _eeprom.display_variant == 15: + return InkyUC8159(resolution=(640, 400)) if ask_user: if verbose: diff --git a/library/inky/eeprom.py b/library/inky/eeprom.py index f73c77c4..bfb1ed60 100644 --- a/library/inky/eeprom.py +++ b/library/inky/eeprom.py @@ -25,7 +25,8 @@ 'Red pHAT (SSD1608)', 'Yellow pHAT (SSD1608)', None, - '7-Colour (UC8159)' + '7-Colour (UC8159)', + '7-Colour 640x400 (UC8159)' ] diff --git a/library/inky/inky_uc8159.py b/library/inky/inky_uc8159.py index f52d630f..24aa9c4b 100644 --- a/library/inky/inky_uc8159.py +++ b/library/inky/inky_uc8159.py @@ -138,35 +138,14 @@ def __init__(self, resolution=(600, 448), colour='multi', cs_pin=CS0_PIN, dc_pin self.eeprom = eeprom.read_eeprom(i2c_bus=i2c_bus) self.lut = colour - # Get resolution from the EEPROM if it's valid + # Check for supported display variant and select the correct resolution # Eg: 600x480 and 640x400 - eeprom_resolution = self.eeprom.width, self.eeprom.height - if eeprom_resolution in _RESOLUTION.keys(): + if self.eeprom.display_variant in (14, 15): + eeprom_resolution = _RESOLUTION.keys[self.eeprom.display_variant - 14] self.resolution = eeprom_resolution self.width, self.height = eeprom_resolution self.cols, self.rows, self.rotation, self.offset_x, self.offset_y, self.resolution_setting = _RESOLUTION[eeprom_resolution] - # The EEPROM is used to disambiguate the variants of wHAT and pHAT - # 1 Red pHAT (High-Temp) - # 2 Yellow wHAT (1_E) - # 3 Black wHAT (1_E) - # 4 Black pHAT (Normal) - # 5 Yellow pHAT (DEP0213YNS75AFICP) - # 6 Red wHAT (Regular) - # 7 Red wHAT (High-Temp) - # 8 Red wHAT (DEPG0420RWS19AF0HP) - # 10 BW pHAT (ssd1608) (DEPG0213BNS800F13CP) - # 11 Red pHAT (ssd1608) - # 12 Yellow pHAT (ssd1608) - # if self.eeprom is not None: - # # Only support new-style variants - # if self.eeprom.display_variant not in (10, 11, 12): - # raise RuntimeError('This driver is not compatible with your board.') - # if self.eeprom.width != self.width or self.eeprom.height != self.height: - # pass - # # TODO flash correct heights to new EEPROMs - # # raise ValueError('Supplied width/height do not match Inky: {}x{}'.format(self.eeprom.width, self.eeprom.height)) - self.buf = numpy.zeros((self.rows, self.cols), dtype=numpy.uint8) self.dc_pin = dc_pin From c67db2c403d9526e8e1cdbebb8adfd0c45c1b5bf Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 2 Dec 2021 14:00:43 +0000 Subject: [PATCH 08/12] Fix typo for #130 --- examples/7color/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/7color/graph.py b/examples/7color/graph.py index e38c5d3e..55f571bd 100755 --- a/examples/7color/graph.py +++ b/examples/7color/graph.py @@ -10,7 +10,7 @@ print(""" -Requires the seaborn library: suso python3 -m pip install seaborn +Requires the seaborn library: sudo python3 -m pip install seaborn You may need to: sudo apt install libatlas-base-dev """) From dc6925f89ad1e4ea02fe3ccde411cd5089067323 Mon Sep 17 00:00:00 2001 From: missionfloyd Date: Tue, 9 Nov 2021 23:52:05 -0700 Subject: [PATCH 09/12] Move fonts to example-depends --- library/README.md | 4 ++-- library/setup.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/README.md b/library/README.md index fe000049..97fd33ab 100644 --- a/library/README.md +++ b/library/README.md @@ -21,10 +21,10 @@ Python library for the [Inky pHAT](https://shop.pimoroni.com/products/inky-phat) The Python pip package is named inky, on the Raspberry Pi install with: ``` -pip3 install inky[rpi,fonts] +pip3 install inky[rpi,example-depends] ``` -This will install Inky along with dependencies for the Raspberry Pi, plus fonts used by the examples. +This will install Inky along with dependencies for the Raspberry Pi, plus modules used by the examples. If you want to simulate Inky on your desktop, use: diff --git a/library/setup.py b/library/setup.py index acf257a1..1dffd835 100755 --- a/library/setup.py +++ b/library/setup.py @@ -56,7 +56,6 @@ extras_require={ 'rpi-gpio-output': ['RPi.GPIO'], 'rpi': ['RPi.GPIO'], - 'fonts': ['font-fredoka-one', 'font-source-serif-pro', 'font-hanken-grotesk', 'font-intuitive'], - 'example-depends': ['requests', 'geocoder', 'beautifulsoup4'] + 'example-depends': ['requests', 'geocoder', 'beautifulsoup4', 'font-fredoka-one', 'font-source-serif-pro', 'font-hanken-grotesk', 'font-intuitive'] } ) From 8bf1f5aff10d4941ba9c8507f19876cd3f6725af Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 2 Dec 2021 14:56:34 +0000 Subject: [PATCH 10/12] Install example-depends --- install.sh | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/install.sh b/install.sh index 70918c35..cbd9bf3a 100755 --- a/install.sh +++ b/install.sh @@ -7,16 +7,15 @@ if [ $(id -u) -ne 0 ]; then exit 1 fi -cd library +function py_install() { + if [ -f "$1" ]; then + VERSION=`$1 --version 2>&1` + printf "Installing for $VERSION..\n" + $1 -m pip install --no-binary .[example-depends] ./library/ + fi +} -printf "Installing for Python 2..\n" -python setup.py install - -if [ -f "/usr/bin/python3" ]; then - printf "Installing for Python 3..\n" - python3 setup.py install -fi - -cd .. +py_install /usr/bin/python +py_install /usr/bin/python3 printf "Done!\n" From 7211b54e98f95b054fa0759fe22b263e3d6d0abd Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 20 Dec 2021 12:23:17 +0000 Subject: [PATCH 11/12] UC8159: Check EEPROM is not None --- library/inky/inky_uc8159.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/inky/inky_uc8159.py b/library/inky/inky_uc8159.py index 24aa9c4b..49446f97 100644 --- a/library/inky/inky_uc8159.py +++ b/library/inky/inky_uc8159.py @@ -140,7 +140,7 @@ def __init__(self, resolution=(600, 448), colour='multi', cs_pin=CS0_PIN, dc_pin # Check for supported display variant and select the correct resolution # Eg: 600x480 and 640x400 - if self.eeprom.display_variant in (14, 15): + if self.eeprom is not None and self.eeprom.display_variant in (14, 15): eeprom_resolution = _RESOLUTION.keys[self.eeprom.display_variant - 14] self.resolution = eeprom_resolution self.width, self.height = eeprom_resolution From 421fe1bbf05c23a5a40b20948e510f804fd5d25e Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 20 Dec 2021 12:42:36 +0000 Subject: [PATCH 12/12] Prep for v1.3.0 --- library/CHANGELOG.txt | 7 +++++++ library/inky/__init__.py | 2 +- library/setup.py | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/CHANGELOG.txt b/library/CHANGELOG.txt index db034edb..2cc9656c 100644 --- a/library/CHANGELOG.txt +++ b/library/CHANGELOG.txt @@ -1,3 +1,10 @@ +1.3.0 +----- + +* New: inky UC8159 support for 4" 640x400 display variant +* BugFix: fix set_image so it doesn't break set_pixel +* New: Added --simulate to "auto()", so auto examples can simulate a chosen board + 1.2.2 ----- diff --git a/library/inky/__init__.py b/library/inky/__init__.py index 498317bd..95343a64 100644 --- a/library/inky/__init__.py +++ b/library/inky/__init__.py @@ -8,7 +8,7 @@ from .inky_uc8159 import Inky as Inky7Colour # noqa: F401 from .auto import auto # noqa: F401 -__version__ = '1.2.2' +__version__ = '1.3.0' try: from pkg_resources import declare_namespace diff --git a/library/setup.py b/library/setup.py index 1dffd835..637ae274 100755 --- a/library/setup.py +++ b/library/setup.py @@ -38,7 +38,7 @@ setup( name='inky', - version='1.2.2', + version='1.3.0', author='Philip Howard', author_email='phil@pimoroni.com', description='Inky pHAT Driver',