Compare commits

..

No commits in common. "main" and "patch" have entirely different histories.
main ... patch

46 changed files with 1056 additions and 2314 deletions

11
.gitattributes vendored
View file

@ -1,11 +0,0 @@
# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
.py text eol=lf
.rst text eol=lf
.txt text eol=lf
.yaml text eol=lf
.toml text eol=lf
.license text eol=lf
.md text eol=lf

View file

@ -4,7 +4,7 @@
Thank you for contributing! Before you submit a pull request, please read the following. Thank you for contributing! Before you submit a pull request, please read the following.
Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://docs.circuitpython.org/en/latest/docs/design_guide.html Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://circuitpython.readthedocs.io/en/latest/docs/design_guide.html
If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs

View file

@ -10,5 +10,66 @@ jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Run Build CI workflow - name: Dump GitHub context
uses: adafruit/workflows-circuitpython-libs/build@main env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install dependencies
# (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.)
run: |
source actions-ci/install.sh
- name: Pip install Sphinx, pre-commit
run: |
pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit
- name: Library version
run: git describe --dirty --always --tags
- name: Pre-commit hooks
run: |
pre-commit run --all-files
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Archive bundles
uses: actions/upload-artifact@v2
with:
name: bundles
path: ${{ github.workspace }}/bundles/
- name: Build docs
working-directory: docs
run: sphinx-build -E -W -b html . _build/html
- name: Check For setup.py
id: need-pypi
run: |
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
- name: Build Python package
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
run: |
pip install --upgrade setuptools wheel twine readme_renderer testresources
python setup.py sdist
python setup.py bdist_wheel --universal
twine check dist/*
- name: Setup problem matchers
uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1

85
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,85 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
name: Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install deps
run: |
source actions-ci/install.sh
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Upload Release Assets
# the 'official' actions version does not yet support dynamically
# supplying asset names to upload. @csexton's version chosen based on
# discussion in the issue below, as its the simplest to implement and
# allows for selecting files with a pattern.
# https://github.com/actions/upload-release-asset/issues/4
#uses: actions/upload-release-asset@v1.0.1
uses: csexton/release-asset-action@master
with:
pattern: "bundles/*"
github-token: ${{ secrets.GITHUB_TOKEN }}
upload-pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Check For setup.py
id: need-pypi
run: |
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
- name: Set up Python
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Install dependencies
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
env:
TWINE_USERNAME: ${{ secrets.pypi_username }}
TWINE_PASSWORD: ${{ secrets.pypi_password }}
run: |
python setup.py sdist
twine upload dist/*

View file

@ -1,19 +0,0 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
name: GitHub Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Run GitHub Release CI workflow
uses: adafruit/workflows-circuitpython-libs/release-gh@main
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
upload-url: ${{ github.event.release.upload_url }}

View file

@ -1,19 +0,0 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
name: PyPI Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Run PyPI Release CI workflow
uses: adafruit/workflows-circuitpython-libs/release-pypi@main
with:
pypi-username: ${{ secrets.pypi_username }}
pypi-password: ${{ secrets.pypi_password }}

55
.gitignore vendored
View file

@ -1,48 +1,15 @@
# SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: Unlicense
# Do not include files and directories created by your personal work environment, such as the IDE
# you use, except for those already listed here. Pull requests including changes to this file will
# not be accepted.
# This .gitignore file contains rules for files generated by working with CircuitPython libraries,
# including building Sphinx, testing with pip, and creating a virual environment, as well as the
# MacOS and IDE-specific files generated by using MacOS in general, or the PyCharm or VSCode IDEs.
# If you find that there are files being generated on your machine that should not be included in
# your git commit, you should create a .gitignore_global file on your computer to include the
# files created by your personal setup. To do so, follow the two steps below.
# First, create a file called .gitignore_global somewhere convenient for you, and add rules for
# the files you want to exclude from git commits.
# Second, configure Git to use the exclude file for all Git repositories by running the
# following via commandline, replacing "path/to/your/" with the actual path to your newly created
# .gitignore_global file:
# git config --global core.excludesfile path/to/your/.gitignore_global
# CircuitPython-specific files
*.mpy *.mpy
# Python-specific files
__pycache__
*.pyc
# Sphinx build-specific files
_build
# This file results from running `pip -e install .` in a local repository
*.egg-info
# Virtual environment-specific files
.env
.venv
# MacOS-specific files
*.DS_Store
# IDE-specific files
.idea .idea
.vscode __pycache__
*~ _build
*.pyc
.env
bundles
*.DS_Store
.eggs
dist
**/*.egg-info

View file

@ -1,21 +1,42 @@
# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries # SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
# #
# SPDX-License-Identifier: Unlicense # SPDX-License-Identifier: Unlicense
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/python/black
rev: v4.5.0 rev: 20.8b1
hooks: hooks:
- id: check-yaml - id: black
- id: end-of-file-fixer - repo: https://github.com/fsfe/reuse-tool
- id: trailing-whitespace rev: v0.12.1
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.4
hooks: hooks:
- id: ruff-format - id: reuse
- id: ruff - repo: https://github.com/pre-commit/pre-commit-hooks
args: ["--fix"] rev: v2.3.0
- repo: https://github.com/fsfe/reuse-tool
rev: v3.0.1
hooks: hooks:
- id: reuse - id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pycqa/pylint
rev: v2.11.1
hooks:
- id: pylint
name: pylint (library code)
types: [python]
args:
- --disable=consider-using-f-string,duplicate-code
exclude: "^(docs/|examples/|tests/|setup.py$)"
- id: pylint
name: pylint (example code)
description: Run pylint rules on "examples/*.py" files
types: [python]
files: "^examples/"
args:
- --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code
- id: pylint
name: pylint (test code)
description: Run pylint rules on "tests/*.py" files
types: [python]
files: "^tests/"
args:
- --disable=missing-docstring,consider-using-f-string,duplicate-code

437
.pylintrc Normal file
View file

@ -0,0 +1,437 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint.
jobs=1
# jobs=2
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation,unspecified-encoding
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
# notes=FIXME,XXX,TODO
notes=FIXME,XXX
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=board
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,future.builtins
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
# expected-line-ending-format=
expected-line-ending-format=LF
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=yes
# Minimum lines number of a similarity.
min-similarity-lines=4
[BASIC]
# Naming hint for argument names
argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct argument names
argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for attribute names
attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct attribute names
attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming hint for class names
# class-name-hint=[A-Z_][a-zA-Z0-9]+$
class-name-hint=[A-Z_][a-zA-Z0-9_]+$
# Regular expression matching correct class names
# class-rgx=[A-Z_][a-zA-Z0-9]+$
class-rgx=[A-Z_][a-zA-Z0-9_]+$
# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming hint for function names
function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct function names
function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Good variable names which should always be accepted, separated by a comma
# good-names=i,j,k,ex,Run,_
good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming hint for method names
method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct method names
method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Naming hint for variable names
variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct variable names
variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Maximum number of attributes for a class (see R0902).
# max-attributes=7
max-attributes=11
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of statements in function / method body
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=1
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

View file

@ -8,15 +8,8 @@
# Required # Required
version: 2 version: 2
sphinx:
configuration: docs/conf.py
build:
os: ubuntu-lts-latest
tools:
python: "3"
python: python:
version: "3.6"
install: install:
- requirements: docs/requirements.txt - requirements: docs/requirements.txt
- requirements: requirements.txt - requirements: requirements.txt

View file

@ -2,10 +2,10 @@ Introduction
============ ============
.. image:: https://readthedocs.org/projects/adafruit-circuitpython-epd/badge/?version=latest .. image:: https://readthedocs.org/projects/adafruit-circuitpython-epd/badge/?version=latest
:target: https://docs.circuitpython.org/projects/epd/en/latest/ :target: https://circuitpython.readthedocs.io/projects/epd/en/latest/
:alt: Documentation Status :alt: Documentation Status
.. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg .. image:: https://img.shields.io/discord/327254708534116352.svg
:target: https://adafru.it/discord :target: https://adafru.it/discord
:alt: Discord :alt: Discord
@ -13,10 +13,6 @@ Introduction
:target: https://github.com/adafruit/Adafruit_CircuitPython_EPD/actions/ :target: https://github.com/adafruit/Adafruit_CircuitPython_EPD/actions/
:alt: Build Status :alt: Build Status
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
:target: https://github.com/astral-sh/ruff
:alt: Code Style: Ruff
This library is for using CircuitPython with e-ink displays with built in SRAM. This library is for using CircuitPython with e-ink displays with built in SRAM.
Dependencies Dependencies
@ -52,8 +48,8 @@ To install in a virtual environment in your current project:
.. code-block:: shell .. code-block:: shell
mkdir project-name && cd project-name mkdir project-name && cd project-name
python3 -m venv .venv python3 -m venv .env
source .venv/bin/activate source .env/bin/activate
pip3 install adafruit-circuitpython-epd pip3 install adafruit-circuitpython-epd
Usage Example Usage Example
@ -104,9 +100,7 @@ Usage Example
Documentation Documentation
============= =============
API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/epd/en/latest/>`_. API documentation for this library can be found on `Read the Docs <https://circuitpython.readthedocs.io/projects/epd/en/latest/>`_.
For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
Contributing Contributing
============ ============
@ -114,3 +108,8 @@ Contributing
Contributions are welcome! Please read our `Code of Conduct Contributions are welcome! Please read our `Code of Conduct
<https://github.com/adafruit/Adafruit_CircuitPython_EPD/blob/main/CODE_OF_CONDUCT.md>`_ <https://github.com/adafruit/Adafruit_CircuitPython_EPD/blob/main/CODE_OF_CONDUCT.md>`_
before contributing to help this project stay welcoming. before contributing to help this project stay welcoming.
Documentation
=============
For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.

View file

@ -1,164 +0,0 @@
# SPDX-FileCopyrightText: 2018 Dean Miller for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_epd.EK79686` - Adafruit EK79686 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit EK79686 display breakouts
* Author(s): Melissa LeBlanc-Williams
"""
import time
import adafruit_framebuf
from micropython import const
from adafruit_epd.epd import Adafruit_EPD
try:
"Needed for type annotations"
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_EK79686_PANEL_SETTING = const(0x00)
_EK79686_POWER_SETTING = const(0x01)
_EK79686_POWER_OFF = const(0x02)
_EK79686_POWER_OFF_SEQUENCE = const(0x03)
_EK79686_POWER_ON = const(0x04)
_EK79686_POWER_ON_MEASURE = const(0x05)
_EK79686_BOOSTER_SOFT_START = const(0x06)
_EK79686_DEEP_SLEEP = const(0x07)
_EK79686_DTM1 = const(0x10)
_EK79686_DATA_STOP = const(0x11)
_EK79686_DISPLAY_REFRESH = const(0x12)
_EK79686_DTM2 = const(0x13)
_EK79686_PDTM1 = const(0x14)
_EK79686_PDTM2 = const(0x15)
_EK79686_PDRF = const(0x16)
_EK79686_LUT1 = const(0x20)
_EK79686_LUTWW = const(0x21)
_EK79686_LUTBW = const(0x22)
_EK79686_LUTWB = const(0x23)
_EK79686_LUTBB = const(0x24)
_EK79686_PLL = const(0x30)
_EK79686_CDI = const(0x50)
_EK79686_RESOLUTION = const(0x61)
_EK79686_VCM_DC_SETTING = const(0x82)
class Adafruit_EK79686(Adafruit_EPD):
"""driver class for Adafruit EK79686 ePaper display breakouts"""
def __init__(
self,
width: int,
height: int,
spi: SPI,
*,
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8)
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray((width * height) // 8)
self._buffer2 = bytearray((width * height) // 8)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB
)
self.set_black_buffer(0, True)
self.set_color_buffer(1, False)
self._single_byte_tx = False
def begin(self, reset: bool = True) -> None:
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self) -> None:
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while not self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self) -> None:
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
time.sleep(0.2)
self.command(_EK79686_PANEL_SETTING, bytearray([0x0F])) # LUT from OTP 176x264
self.command(0x4D, bytearray([0xAA])) # FITI cmd (???)
self.command(0x87, bytearray([0x28]))
self.command(0x84, bytearray([0x00]))
self.command(0x83, bytearray([0x05]))
self.command(0xA8, bytearray([0xDF]))
self.command(0xA9, bytearray([0x05]))
self.command(0xB1, bytearray([0xE8]))
self.command(0xAB, bytearray([0xA1]))
self.command(0xB9, bytearray([0x10]))
self.command(0x88, bytearray([0x80]))
self.command(0x90, bytearray([0x02]))
self.command(0x86, bytearray([0x15]))
self.command(0x91, bytearray([0x8D]))
self.command(0xAA, bytearray([0x0F]))
self.command(_EK79686_POWER_ON)
self.busy_wait()
def power_down(self) -> None:
"""Power down the display - required when not actively displaying!"""
self.command(_EK79686_POWER_OFF, bytearray([0x17]))
self.busy_wait()
if self._rst: # Only deep sleep if we can get out of it
self.command(_EK79686_DEEP_SLEEP, bytearray([0xA5]))
def update(self) -> None:
"""Update the display from internal memory"""
self.command(_EK79686_DISPLAY_REFRESH)
self.busy_wait()
if not self._busy:
time.sleep(16) # wait 16 seconds
def write_ram(self, index: Literal[0, 1]) -> int:
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_EK79686_DTM1, end=False)
if index == 1:
return self.command(_EK79686_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
return # on this chip it does nothing

View file

@ -10,29 +10,15 @@ CircuitPython driver for Adafruit ePaper display breakouts
""" """
import time import time
from digitalio import Direction
from micropython import const from micropython import const
from digitalio import Direction
from adafruit_epd import mcp_sram from adafruit_epd import mcp_sram
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
from typing import Any, Callable, Optional, Union
from busio import SPI
from circuitpython_typing.pil import Image
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
class Adafruit_EPD: class Adafruit_EPD: # pylint: disable=too-many-instance-attributes, too-many-public-methods
"""Base class for EPD displays""" """Base class for EPD displays"""
BLACK = const(0) BLACK = const(0)
@ -43,16 +29,8 @@ class Adafruit_EPD:
LIGHT = const(5) LIGHT = const(5)
def __init__( def __init__(
self, self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ): # pylint: disable=too-many-arguments
height: int,
spi: SPI,
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
self._width = width self._width = width
self._height = height self._height = height
@ -98,7 +76,7 @@ class Adafruit_EPD:
self._black_inverted = self._color_inverted = True self._black_inverted = self._color_inverted = True
self.hardware_reset() self.hardware_reset()
def display(self) -> None: def display(self): # pylint: disable=too-many-branches
"""show the contents of the display buffer""" """show the contents of the display buffer"""
self.power_up() self.power_up()
@ -129,7 +107,8 @@ class Adafruit_EPD:
databyte = self._spi_transfer(databyte) databyte = self._spi_transfer(databyte)
self.sram.cs_pin.value = True self.sram.cs_pin.value = True
else: else:
self._spi_transfer(self._buffer1) for databyte in self._buffer1:
self._spi_transfer(databyte)
self._cs.value = True self._cs.value = True
self.spi_device.unlock() self.spi_device.unlock()
@ -161,16 +140,18 @@ class Adafruit_EPD:
databyte = self._spi_transfer(databyte) databyte = self._spi_transfer(databyte)
self.sram.cs_pin.value = True self.sram.cs_pin.value = True
else: else:
self._spi_transfer(self._buffer2) for databyte in self._buffer2:
self._spi_transfer(databyte)
self._cs.value = True self._cs.value = True
self.spi_device.unlock() self.spi_device.unlock()
elif self.sram: else:
self.sram.cs_pin.value = True if self.sram:
self.sram.cs_pin.value = True
self.update() self.update()
def hardware_reset(self) -> None: def hardware_reset(self):
"""If we have a reset pin, do a hardware reset by toggling it""" """If we have a reset pin, do a hardware reset by toggling it"""
if self._rst: if self._rst:
self._rst.value = False self._rst.value = False
@ -178,7 +159,7 @@ class Adafruit_EPD:
self._rst.value = True self._rst.value = True
time.sleep(0.1) time.sleep(0.1)
def command(self, cmd: int, data: Optional[bytearray] = None, end: bool = True) -> int: def command(self, cmd, data=None, end=True):
"""Send command byte to display.""" """Send command byte to display."""
self._cs.value = True self._cs.value = True
self._dc.value = False self._dc.value = False
@ -190,64 +171,48 @@ class Adafruit_EPD:
if data is not None: if data is not None:
self._dc.value = True self._dc.value = True
self._spi_transfer(data) for b in data:
self._spi_transfer(b)
if end: if end:
self._cs.value = True self._cs.value = True
self.spi_device.unlock() self.spi_device.unlock()
return ret return ret
def _spi_transfer(self, data: Union[int, bytearray]) -> Optional[int]: def _spi_transfer(self, databyte):
"""Transfer one byte or bytearray, toggling the cs pin if required by the EPD chipset""" """Transfer one byte, toggling the cs pin if required by the EPD chipset"""
if isinstance(data, int): # single byte! self._spibuf[0] = databyte
self._spibuf[0] = data if self._single_byte_tx:
self._cs.value = False
self.spi_device.write_readinto(self._spibuf, self._spibuf)
if self._single_byte_tx:
self._cs.value = True
return self._spibuf[0]
# easy & fast case: array and no twiddling def power_up(self):
if not self._single_byte_tx and isinstance(data, bytearray):
self.spi_device.write(data)
return None
# if its a single byte
if isinstance(data, int): # single byte!
if self._single_byte_tx:
self._cs.value = False
try:
self.spi_device.write_readinto(self._spibuf, self._spibuf)
except NotImplementedError:
self.spi_device.write(self._spibuf)
if self._single_byte_tx:
self._cs.value = True
return self._spibuf[0]
if isinstance(data, bytearray):
for x in data:
self._spi_transfer(x)
return None
def power_up(self) -> None:
"""Power up the display in preparation for writing RAM and updating. """Power up the display in preparation for writing RAM and updating.
must be implemented in subclass""" must be implemented in subclass"""
raise NotImplementedError() raise NotImplementedError()
def power_down(self) -> None: def power_down(self):
"""Power down the display, must be implemented in subclass""" """Power down the display, must be implemented in subclass"""
raise NotImplementedError() raise NotImplementedError()
def update(self) -> None: def update(self):
"""Update the display from internal memory, must be implemented in subclass""" """Update the display from internal memory, must be implemented in subclass"""
raise NotImplementedError() raise NotImplementedError()
def write_ram(self, index: int) -> None: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays. must be implemented in subclass""" 0 or 1 for tri-color displays. must be implemented in subclass"""
raise NotImplementedError() raise NotImplementedError()
def set_ram_address(self, x: int, y: int) -> None: def set_ram_address(self, x, y):
"""Set the RAM address location, must be implemented in subclass""" """Set the RAM address location, must be implemented in subclass"""
raise NotImplementedError() raise NotImplementedError()
def set_black_buffer(self, index: Literal[0, 1], inverted: bool) -> None: def set_black_buffer(self, index, inverted):
"""Set the index for the black buffer data (0 or 1) and whether its inverted""" """Set the index for the black buffer data (0 or 1) and whether its inverted"""
if index == 0: if index == 0:
self._blackframebuf = self._framebuf1 self._blackframebuf = self._framebuf1
@ -257,7 +222,7 @@ class Adafruit_EPD:
raise RuntimeError("Buffer index must be 0 or 1") raise RuntimeError("Buffer index must be 0 or 1")
self._black_inverted = inverted self._black_inverted = inverted
def set_color_buffer(self, index: Literal[0, 1], inverted: bool) -> None: def set_color_buffer(self, index, inverted):
"""Set the index for the color buffer data (0 or 1) and whether its inverted""" """Set the index for the color buffer data (0 or 1) and whether its inverted"""
if index == 0: if index == 0:
self._colorframebuf = self._framebuf1 self._colorframebuf = self._framebuf1
@ -267,12 +232,7 @@ class Adafruit_EPD:
raise RuntimeError("Buffer index must be 0 or 1") raise RuntimeError("Buffer index must be 0 or 1")
self._color_inverted = inverted self._color_inverted = inverted
def _color_dup( def _color_dup(self, func, args, color):
self,
func: Callable,
args: Any,
color: Literal[0, 1, 2, 3, 4, 5],
) -> None:
black = getattr(self._blackframebuf, func) black = getattr(self._blackframebuf, func)
red = getattr(self._colorframebuf, func) red = getattr(self._colorframebuf, func)
if self._blackframebuf is self._colorframebuf: # monochrome if self._blackframebuf is self._colorframebuf: # monochrome
@ -281,11 +241,11 @@ class Adafruit_EPD:
black(*args, color=(color == Adafruit_EPD.BLACK) != self._black_inverted) black(*args, color=(color == Adafruit_EPD.BLACK) != self._black_inverted)
red(*args, color=(color == Adafruit_EPD.RED) != self._color_inverted) red(*args, color=(color == Adafruit_EPD.RED) != self._color_inverted)
def pixel(self, x: int, y: int, color: int) -> None: def pixel(self, x, y, color):
"""draw a single pixel in the display buffer""" """draw a single pixel in the display buffer"""
self._color_dup("pixel", (x, y), color) self._color_dup("pixel", (x, y), color)
def fill(self, color: int) -> None: def fill(self, color):
"""fill the screen with the passed color""" """fill the screen with the passed color"""
red_fill = ((color == Adafruit_EPD.RED) != self._color_inverted) * 0xFF red_fill = ((color == Adafruit_EPD.RED) != self._color_inverted) * 0xFF
black_fill = ((color == Adafruit_EPD.BLACK) != self._black_inverted) * 0xFF black_fill = ((color == Adafruit_EPD.BLACK) != self._black_inverted) * 0xFF
@ -297,28 +257,21 @@ class Adafruit_EPD:
self._blackframebuf.fill(black_fill) self._blackframebuf.fill(black_fill)
self._colorframebuf.fill(red_fill) self._colorframebuf.fill(red_fill)
def rect(self, x: int, y: int, width: int, height: int, color: int) -> None: def rect(self, x, y, width, height, color): # pylint: disable=too-many-arguments
"""draw a rectangle""" """draw a rectangle"""
self._color_dup("rect", (x, y, width, height), color) self._color_dup("rect", (x, y, width, height), color)
def fill_rect(self, x: int, y: int, width: int, height: int, color: int) -> None: def fill_rect(
self, x, y, width, height, color
): # pylint: disable=too-many-arguments
"""fill a rectangle with the passed color""" """fill a rectangle with the passed color"""
self._color_dup("fill_rect", (x, y, width, height), color) self._color_dup("fill_rect", (x, y, width, height), color)
def line(self, x_0: int, y_0: int, x_1: int, y_1: int, color: int) -> None: def line(self, x_0, y_0, x_1, y_1, color): # pylint: disable=too-many-arguments
"""Draw a line from (x_0, y_0) to (x_1, y_1) in passed color""" """Draw a line from (x_0, y_0) to (x_1, y_1) in passed color"""
self._color_dup("line", (x_0, y_0, x_1, y_1), color) self._color_dup("line", (x_0, y_0, x_1, y_1), color)
def text( def text(self, string, x, y, color, *, font_name="font5x8.bin", size=1):
self,
string: str,
x: int,
y: int,
color: int,
*,
font_name: str = "font5x8.bin",
size: int = 1,
) -> None:
"""Write text string at location (x, y) in given color, using font file""" """Write text string at location (x, y) in given color, using font file"""
if self._blackframebuf is self._colorframebuf: # monochrome if self._blackframebuf is self._colorframebuf: # monochrome
self._blackframebuf.text( self._blackframebuf.text(
@ -348,58 +301,48 @@ class Adafruit_EPD:
) )
@property @property
def width(self) -> int: def width(self):
"""The width of the display, accounting for rotation""" """The width of the display, accounting for rotation"""
if self.rotation in {0, 2}: if self.rotation in (0, 2):
return self._width return self._width
return self._height return self._height
@property @property
def height(self) -> int: def height(self):
"""The height of the display, accounting for rotation""" """The height of the display, accounting for rotation"""
if self.rotation in {0, 2}: if self.rotation in (0, 2):
return self._height return self._height
return self._width return self._width
@property @property
def rotation(self) -> Literal[0, 1, 2, 3]: def rotation(self):
"""The rotation of the display, can be one of (0, 1, 2, 3)""" """The rotation of the display, can be one of (0, 1, 2, 3)"""
return self._framebuf1.rotation return self._framebuf1.rotation
@rotation.setter @rotation.setter
def rotation(self, val: int) -> None: def rotation(self, val):
self._framebuf1.rotation = val self._framebuf1.rotation = val
if self._framebuf2: if self._framebuf2:
self._framebuf2.rotation = val self._framebuf2.rotation = val
def hline( def hline(self, x, y, width, color):
self,
x: int,
y: int,
width: int,
color: int,
) -> None:
"""draw a horizontal line""" """draw a horizontal line"""
self.fill_rect(x, y, width, 1, color) self.fill_rect(x, y, width, 1, color)
def vline( def vline(self, x, y, height, color):
self,
x: int,
y: int,
height: int,
color: int,
) -> None:
"""draw a vertical line""" """draw a vertical line"""
self.fill_rect(x, y, 1, height, color) self.fill_rect(x, y, 1, height, color)
def image(self, image: Image) -> None: def image(self, image):
"""Set buffer to value of Python Imaging Library image. The image should """Set buffer to value of Python Imaging Library image. The image should
be in RGB mode and a size equal to the display size. be in RGB mode and a size equal to the display size.
""" """
imwidth, imheight = image.size imwidth, imheight = image.size
if imwidth != self.width or imheight != self.height: if imwidth != self.width or imheight != self.height:
raise ValueError( raise ValueError(
f"Image must be same dimensions as display ({self.width}x{self.height})." "Image must be same dimensions as display ({0}x{1}).".format(
self.width, self.height
)
) )
if self.sram: if self.sram:
raise RuntimeError("PIL image is not for use with SRAM assist") raise RuntimeError("PIL image is not for use with SRAM assist")

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit il0373 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_IL0373_PANEL_SETTING = const(0x00) _IL0373_PANEL_SETTING = const(0x00)
@ -59,19 +46,13 @@ _IL0373_VCM_DC_SETTING = const(0x82)
class Adafruit_IL0373(Adafruit_EPD): class Adafruit_IL0373(Adafruit_EPD):
"""driver class for Adafruit IL0373 ePaper display breakouts""" """driver class for Adafruit IL0373 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
self._buffer1_size = int(width * height / 8) self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8) self._buffer2_size = int(width * height / 8)
@ -94,13 +75,13 @@ class Adafruit_IL0373(Adafruit_EPD):
self.set_color_buffer(1, True) self.set_color_buffer(1, True)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -109,7 +90,7 @@ class Adafruit_IL0373(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
self.busy_wait() self.busy_wait()
@ -131,13 +112,13 @@ class Adafruit_IL0373(Adafruit_EPD):
self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A]))
time.sleep(0.05) time.sleep(0.05)
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_IL0373_CDI, bytearray([0x17])) self.command(_IL0373_CDI, bytearray([0x17]))
self.command(_IL0373_VCM_DC_SETTING, bytearray([0x00])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x00]))
self.command(_IL0373_POWER_OFF) self.command(_IL0373_POWER_OFF)
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_IL0373_DISPLAY_REFRESH) self.command(_IL0373_DISPLAY_REFRESH)
time.sleep(0.1) time.sleep(0.1)
@ -145,7 +126,7 @@ class Adafruit_IL0373(Adafruit_EPD):
if not self._busy: if not self._busy:
time.sleep(15) # wait 15 seconds time.sleep(15) # wait 15 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -155,7 +136,7 @@ class Adafruit_IL0373(Adafruit_EPD):
return self.command(_IL0373_DTM2, end=False) return self.command(_IL0373_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
return # on this chip it does nothing return # on this chip it does nothing

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit IL0398 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_IL0398_PANEL_SETTING = const(0x00) _IL0398_PANEL_SETTING = const(0x00)
@ -60,19 +47,13 @@ _IL0398_VCM_DC_SETTING = const(0x82)
class Adafruit_IL0398(Adafruit_EPD): class Adafruit_IL0398(Adafruit_EPD):
"""driver class for Adafruit IL0373 ePaper display breakouts""" """driver class for Adafruit IL0373 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
self._buffer1_size = int(width * height / 8) self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8) self._buffer2_size = int(width * height / 8)
@ -95,13 +76,13 @@ class Adafruit_IL0398(Adafruit_EPD):
self.set_color_buffer(1, True) self.set_color_buffer(1, True)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -111,7 +92,7 @@ class Adafruit_IL0398(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
self.busy_wait() self.busy_wait()
@ -130,14 +111,14 @@ class Adafruit_IL0398(Adafruit_EPD):
self.command(_IL0398_RESOLUTION, bytearray([_b0, _b1, _b2, _b3])) self.command(_IL0398_RESOLUTION, bytearray([_b0, _b1, _b2, _b3]))
time.sleep(0.05) time.sleep(0.05)
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_IL0398_CDI, bytearray([0xF7])) self.command(_IL0398_CDI, bytearray([0xF7]))
self.command(_IL0398_POWER_OFF) self.command(_IL0398_POWER_OFF)
self.busy_wait() self.busy_wait()
self.command(_IL0398_DEEP_SLEEP, bytearray([0xA5])) self.command(_IL0398_DEEP_SLEEP, bytearray([0xA5]))
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_IL0398_DISPLAY_REFRESH) self.command(_IL0398_DISPLAY_REFRESH)
time.sleep(0.1) time.sleep(0.1)
@ -145,7 +126,7 @@ class Adafruit_IL0398(Adafruit_EPD):
if not self._busy: if not self._busy:
time.sleep(15) # wait 15 seconds time.sleep(15) # wait 15 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -155,7 +136,7 @@ class Adafruit_IL0398(Adafruit_EPD):
return self.command(_IL0398_DTM2, end=False) return self.command(_IL0398_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
return # on this chip it does nothing return # on this chip it does nothing

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit IL91874 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"Needed for type annotations"
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_IL91874_PANEL_SETTING = const(0x00) _IL91874_PANEL_SETTING = const(0x00)
@ -55,29 +42,25 @@ _IL91874_CDI = const(0x50)
_IL91874_RESOLUTION = const(0x61) _IL91874_RESOLUTION = const(0x61)
_IL91874_VCM_DC_SETTING = const(0x82) _IL91874_VCM_DC_SETTING = const(0x82)
_LUT_VCOMDC = b"\x00\x00\x00\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x00\x0e\x01\x0e\x01\x10\x00\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01" # noqa: E501 # pylint: disable=line-too-long
_LUT_WW = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01" # noqa: E501 _LUT_VCOMDC = b"\x00\x00\x00\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x00\x0e\x01\x0e\x01\x10\x00\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
_LUT_BW = b"\xa0\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x90\n\n\x00\x00\x08\xb0\x04\x10\x00\x00\x05\xb0\x03\x0e\x00\x00\n\xc0#\x00\x00\x00\x01" # noqa: E501 _LUT_WW = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
_LUT_BB = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01" # noqa: E501 _LUT_BW = b"\xa0\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x90\n\n\x00\x00\x08\xb0\x04\x10\x00\x00\x05\xb0\x03\x0e\x00\x00\n\xc0#\x00\x00\x00\x01"
_LUT_WB = b"\x90\x1a\x1a\x00\x00\x01 \n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x10\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01" # noqa: E501 _LUT_BB = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
_LUT_WB = b"\x90\x1a\x1a\x00\x00\x01 \n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x10\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
# pylint: enable=line-too-long
class Adafruit_IL91874(Adafruit_EPD): class Adafruit_IL91874(Adafruit_EPD):
"""driver class for Adafruit IL91874 ePaper display breakouts""" """driver class for Adafruit IL91874 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
self._buffer1_size = int(width * height / 8) self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8) self._buffer2_size = int(width * height / 8)
@ -100,14 +83,14 @@ class Adafruit_IL91874(Adafruit_EPD):
self.set_color_buffer(1, False) self.set_color_buffer(1, False)
self._single_byte_tx = True self._single_byte_tx = True
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -116,7 +99,7 @@ class Adafruit_IL91874(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
time.sleep(0.2) time.sleep(0.2)
@ -151,7 +134,7 @@ class Adafruit_IL91874(Adafruit_EPD):
self.command(_IL91874_RESOLUTION, bytearray([_b0, _b1, _b2, _b3])) self.command(_IL91874_RESOLUTION, bytearray([_b0, _b1, _b2, _b3]))
self.command(_IL91874_PDRF, bytearray([0x00])) self.command(_IL91874_PDRF, bytearray([0x00]))
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_IL91874_POWER_OFF, bytearray([0x17])) self.command(_IL91874_POWER_OFF, bytearray([0x17]))
self.busy_wait() self.busy_wait()
@ -159,14 +142,14 @@ class Adafruit_IL91874(Adafruit_EPD):
if self._rst: # Only deep sleep if we can get out of it if self._rst: # Only deep sleep if we can get out of it
self.command(_IL91874_DEEP_SLEEP, bytearray([0xA5])) self.command(_IL91874_DEEP_SLEEP, bytearray([0xA5]))
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_IL91874_DISPLAY_REFRESH) self.command(_IL91874_DISPLAY_REFRESH)
self.busy_wait() self.busy_wait()
if not self._busy: if not self._busy:
time.sleep(16) # wait 16 seconds time.sleep(16) # wait 16 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -176,7 +159,7 @@ class Adafruit_IL91874(Adafruit_EPD):
return self.command(_IL91874_DTM2, end=False) return self.command(_IL91874_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
return # on this chip it does nothing return # on this chip it does nothing

View file

@ -1,467 +0,0 @@
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_epd.jd79661` - Adafruit JD79661 - quad-color ePaper display driver
====================================================================================
CircuitPython driver for Adafruit JD79661 quad-color display breakouts
* Author(s): Liz Clark
"""
import time
import adafruit_framebuf
from micropython import const
from adafruit_epd.epd import Adafruit_EPD
try:
"""Needed for type annotations"""
import typing
from busio import SPI
from circuitpython_typing.pil import Image
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
# Command constants
_JD79661_PANEL_SETTING = const(0x00)
_JD79661_POWER_SETTING = const(0x01)
_JD79661_POWER_OFF = const(0x02)
_JD79661_POWER_ON = const(0x04)
_JD79661_BOOSTER_SOFTSTART = const(0x06)
_JD79661_DEEP_SLEEP = const(0x07)
_JD79661_DATA_START_XMIT = const(0x10)
_JD79661_DISPLAY_REFRESH = const(0x12)
_JD79661_PLL_CONTROL = const(0x30)
_JD79661_CDI = const(0x50)
_JD79661_RESOLUTION = const(0x61)
# Color constants for internal use (2-bit values)
_JD79661_BLACK = const(0b00)
_JD79661_WHITE = const(0b01)
_JD79661_YELLOW = const(0b10)
_JD79661_RED = const(0b11)
# Other command constants from init sequence
_JD79661_POFS = const(0x03)
_JD79661_TCON = const(0x60)
_JD79661_CMD_E7 = const(0xE7)
_JD79661_CMD_E3 = const(0xE3)
_JD79661_CMD_B4 = const(0xB4)
_JD79661_CMD_B5 = const(0xB5)
_JD79661_CMD_E9 = const(0xE9)
_JD79661_CMD_4D = const(0x4D)
class Adafruit_JD79661(Adafruit_EPD):
"""Driver for the JD79661 quad-color ePaper display breakouts"""
BLACK = const(0) # 0b00 in the display buffer
WHITE = const(1) # 0b01 in the display buffer
YELLOW = const(2) # 0b10 in the display buffer
RED = const(3) # 0b11 in the display buffer
def __init__(
self,
width: int,
height: int,
spi: SPI,
*,
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
"""Initialize the quad-color display driver.
Note: This driver uses a different buffer architecture than the parent class.
Instead of separate black and color buffers, it uses a single buffer with
2 bits per pixel to represent 4 colors.
"""
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
stride = width
if stride % 8 != 0:
stride += 8 - stride % 8
self._buffer1_size = int(stride * height / 4)
self._buffer2_size = 0 # No second buffer for this display
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self._buffer1
else:
self._buffer1 = bytearray(self._buffer1_size)
self._buffer2 = self._buffer1
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1,
width,
height,
stride=stride,
buf_format=adafruit_framebuf.MHMSB,
)
self._framebuf2 = self._framebuf1 # Same framebuffer for compatibility
# Set single byte transactions
self._single_byte_tx = True
# Set up buffer references for parent class compatibility
# Both point to the same buffer since we don't have separate color planes
self.set_black_buffer(0, False)
self.set_color_buffer(0, False)
# Initialize with default fill
self.fill(Adafruit_JD79661.WHITE)
def begin(self, reset: bool = True) -> None:
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
time.sleep(0.1)
self.power_down()
def busy_wait(self) -> None:
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing. Note: JD79661 busy is HIGH when busy"""
if self._busy:
while not self._busy.value: # Wait for busy HIGH
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self) -> None:
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
self.busy_wait()
# Send initialization sequence
time.sleep(0.01) # Wait 10ms
self.command(_JD79661_CMD_4D, bytearray([0x78]))
self.command(
_JD79661_PANEL_SETTING, bytearray([0x8F, 0x29])
) # PSR, Display resolution is 128x250
self.command(_JD79661_POWER_SETTING, bytearray([0x07, 0x00])) # PWR
self.command(_JD79661_POFS, bytearray([0x10, 0x54, 0x44])) # POFS
self.command(
_JD79661_BOOSTER_SOFTSTART, bytearray([0x05, 0x00, 0x3F, 0x0A, 0x25, 0x12, 0x1A])
)
self.command(_JD79661_CDI, bytearray([0x37])) # CDI
self.command(_JD79661_TCON, bytearray([0x02, 0x02])) # TCON
self.command(_JD79661_RESOLUTION, bytearray([0, 128, 0, 250])) # TRES
self.command(_JD79661_CMD_E7, bytearray([0x1C]))
self.command(_JD79661_CMD_E3, bytearray([0x22]))
self.command(_JD79661_CMD_B4, bytearray([0xD0]))
self.command(_JD79661_CMD_B5, bytearray([0x03]))
self.command(_JD79661_CMD_E9, bytearray([0x01]))
self.command(_JD79661_PLL_CONTROL, bytearray([0x08]))
self.command(_JD79661_POWER_ON)
self.busy_wait()
def power_down(self) -> None:
"""Power down the display - required when not actively displaying!"""
if self._rst:
self.command(_JD79661_POWER_OFF, bytearray([0x00]))
self.busy_wait()
self.command(_JD79661_DEEP_SLEEP, bytearray([0xA5]))
time.sleep(0.1)
def update(self) -> None:
"""Update the display from internal memory"""
self.command(_JD79661_DISPLAY_REFRESH, bytearray([0x00]))
self.busy_wait()
if not self._busy:
time.sleep(1) # Wait 1 second if no busy pin
def write_ram(self, index: Literal[0, 1]) -> int:
"""Send the one byte command for starting the RAM write process."""
# JD79661 uses same command for all data
return self.command(_JD79661_DATA_START_XMIT, end=False)
def set_ram_address(self, x: int, y: int) -> None:
"""Set the RAM address location."""
# Not used for JD79661
pass
def fill(self, color: int) -> None:
"""Fill the entire display with the specified color.
Args:
color: Color value (BLACK, WHITE, YELLOW, or RED)
Raises:
ValueError: If an invalid color is specified
"""
# Map colors to fill patterns (4 pixels per byte)
color_map = {
Adafruit_JD79661.BLACK: 0x00, # 0b00000000 - all pixels black
Adafruit_JD79661.WHITE: 0x55, # 0b01010101 - all pixels white
Adafruit_JD79661.YELLOW: 0xAA, # 0b10101010 - all pixels yellow
Adafruit_JD79661.RED: 0xFF, # 0b11111111 - all pixels red
}
if color not in color_map:
raise ValueError(
f"Invalid color: {color}. Use BLACK (0), WHITE (1), YELLOW (2), or RED (3)."
)
fill_byte = color_map[color]
if self.sram:
self.sram.erase(0x00, self._buffer1_size, fill_byte)
else:
for i in range(self._buffer1_size):
self._buffer1[i] = fill_byte
def pixel(self, x: int, y: int, color: int) -> None:
"""Draw a single pixel in the display buffer.
Args:
x: X coordinate
y: Y coordinate
color: Color value (BLACK, WHITE, YELLOW, or RED)
"""
if (x < 0) or (x >= self.width) or (y < 0) or (y >= self.height):
return
# Handle rotation
if self.rotation == 1:
x, y = y, x
x = self._width - x - 1
if self._width % 8 != 0:
x -= self._width % 8
elif self.rotation == 2:
x = self._width - x - 1
y = self._height - y - 1
if self._width % 8 != 0:
x += self._width % 8
elif self.rotation == 3:
x, y = y, x
y = self._height - y - 1
# Calculate stride (width adjusted to be divisible by 8)
stride = self._width
if stride % 8 != 0:
stride += 8 - stride % 8
# Map color constants to 2-bit values
color_map = {
Adafruit_JD79661.BLACK: _JD79661_BLACK,
Adafruit_JD79661.WHITE: _JD79661_WHITE,
Adafruit_JD79661.YELLOW: _JD79661_YELLOW,
Adafruit_JD79661.RED: _JD79661_RED,
}
if color not in color_map:
# Default to white for invalid colors
pixel_color = _JD79661_WHITE
else:
pixel_color = color_map[color]
# Calculate byte address (4 pixels per byte)
addr = (x + y * stride) // 4
# Calculate bit offset within byte (2 bits per pixel)
# Pixels are packed left-to-right, MSB first
bit_offset = (3 - (x % 4)) * 2
# Create masks
byte_mask = 0x3 << bit_offset
byte_value = (pixel_color & 0x3) << bit_offset
# Read, modify, write
if self.sram:
current = self.sram.read8(addr)
current &= ~byte_mask
current |= byte_value
self.sram.write8(addr, current)
else:
self._buffer1[addr] &= ~byte_mask
self._buffer1[addr] |= byte_value
def rect(self, x: int, y: int, width: int, height: int, color: int) -> None:
"""Draw a rectangle.
Overridden to use the quad-color pixel method.
"""
for i in range(x, x + width):
self.pixel(i, y, color)
self.pixel(i, y + height - 1, color)
for j in range(y + 1, y + height - 1):
self.pixel(x, j, color)
self.pixel(x + width - 1, j, color)
def fill_rect(self, x: int, y: int, width: int, height: int, color: int) -> None:
"""Fill a rectangle with the passed color.
Overridden to use the quad-color pixel method.
"""
for i in range(x, x + width):
for j in range(y, y + height):
self.pixel(i, j, color)
def line(self, x_0: int, y_0: int, x_1: int, y_1: int, color: int) -> None:
"""Draw a line from (x_0, y_0) to (x_1, y_1) in passed color.
Overridden to use the quad-color pixel method.
"""
dx = abs(x_1 - x_0)
dy = abs(y_1 - y_0)
sx = 1 if x_0 < x_1 else -1
sy = 1 if y_0 < y_1 else -1
err = dx - dy
while True:
self.pixel(x_0, y_0, color)
if x_0 == x_1 and y_0 == y_1:
break
e2 = 2 * err
if e2 > -dy:
err -= dy
x_0 += sx
if e2 < dx:
err += dx
y_0 += sy
def text(
self,
string: str,
x: int,
y: int,
color: int,
*,
font_name: str = "font5x8.bin",
size: int = 1,
) -> None:
"""Write text string at location (x, y) in given color, using font file."""
color_map = {
Adafruit_JD79661.BLACK: _JD79661_BLACK,
Adafruit_JD79661.WHITE: _JD79661_WHITE,
Adafruit_JD79661.YELLOW: _JD79661_YELLOW,
Adafruit_JD79661.RED: _JD79661_RED,
}
if color not in color_map:
raise ValueError(
f"Invalid color: {color}. Use BLACK (0), WHITE (1), YELLOW (2), or RED (3)."
)
text_width = len(string) * 6 * size
text_height = 8 * size
text_width = min(text_width, self.width - x)
text_height = min(text_height, self.height - y)
if text_width <= 0 or text_height <= 0:
return
temp_buf_width = ((text_width + 7) // 8) * 8
temp_buf = bytearray((temp_buf_width * text_height) // 8)
temp_fb = adafruit_framebuf.FrameBuffer(
temp_buf, temp_buf_width, text_height, buf_format=adafruit_framebuf.MHMSB
)
temp_fb.fill(0)
temp_fb.text(string, 0, 0, 1, font_name=font_name, size=size)
for j in range(text_height):
for i in range(text_width):
byte_index = (j * temp_buf_width + i) // 8
bit_index = 7 - ((j * temp_buf_width + i) % 8)
if byte_index < len(temp_buf):
if (temp_buf[byte_index] >> bit_index) & 1:
self.pixel(x + i, y + j, color)
def image(self, image: Image) -> None:
"""Set buffer to value of Python Imaging Library image. The image should
be in RGB mode and a size equal to the display size.
"""
imwidth, imheight = image.size
if imwidth != self.width or imheight != self.height:
raise ValueError(
f"Image must be same dimensions as display ({self.width}x{self.height})."
)
if self.sram:
raise RuntimeError("PIL image is not for use with SRAM assist")
# Grab all the pixels from the image, faster than getpixel.
pix = image.load()
# Clear out any display buffers (assuming white background)
self.fill(Adafruit_JD79661.WHITE)
if image.mode == "RGB": # RGB Mode
for y in range(image.size[1]):
for x in range(image.size[0]):
pixel = pix[x, y]
r, g, b = pixel[0], pixel[1], pixel[2]
# Calculate brightness/luminance for better color detection
brightness = (r + g + b) / 3
# Color detection logic with thresholds
if brightness >= 200: # Light colors -> White
# White is typically the default, so we might not need to set it
# self.pixel(x, y, Adafruit_EPD.WHITE)
pass
elif r >= 128 and g >= 128 and b < 80: # Yellow detection
# High red and green, low blue
self.pixel(x, y, Adafruit_JD79661.YELLOW)
elif r >= 128 and g < 80 and b < 80: # Red detection
# High red, low green and blue
self.pixel(x, y, Adafruit_JD79661.RED)
elif brightness < 80: # Dark colors -> Black
# All RGB values are low
self.pixel(x, y, Adafruit_JD79661.BLACK)
elif r > g and r > b and r >= 100:
# Red-dominant
self.pixel(x, y, Adafruit_JD79661.RED)
elif r >= 100 and g >= 100:
# Both red and green high -> Yellow
self.pixel(x, y, Adafruit_JD79661.YELLOW)
elif brightness < 128:
# Medium-dark -> Black
self.pixel(x, y, Adafruit_JD79661.BLACK)
# else: remains white (default)
elif image.mode == "L": # Grayscale Mode
for y in range(image.size[1]):
for x in range(image.size[0]):
pixel = pix[x, y]
# Map grayscale to 4 levels
if pixel < 64:
self.pixel(x, y, Adafruit_JD79661.BLACK)
elif pixel < 128:
self.pixel(x, y, Adafruit_JD79661.RED) # Or could use YELLOW
elif pixel < 192:
self.pixel(x, y, Adafruit_JD79661.YELLOW)
# else: pixel >= 192 -> WHITE (default)
elif image.mode == "P": # Palette Mode (optional, for indexed color)
# Convert to RGB first for easier processing
rgb_image = image.convert("RGB")
self.image(rgb_image) # Recursive call with RGB image
else:
raise ValueError("Image must be in mode RGB, L, or P.")
def set_black_buffer(self, index: Literal[0, 1], inverted: bool) -> None:
"""Set the index for the black buffer data."""
super().set_black_buffer(index, inverted)
def set_color_buffer(self, index: Literal[0, 1], inverted: bool) -> None:
"""Set the index for the color buffer data."""
super().set_color_buffer(index, inverted)

View file

@ -9,36 +9,27 @@ CircuitPython driver for Microchip SRAM chips
* Author(s): Dean Miller * Author(s): Dean Miller
""" """
from adafruit_bus_device import spi_device
from micropython import const from micropython import const
from adafruit_bus_device import spi_device
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
from typing import Any, List
from busio import SPI
from digitalio import DigitalInOut
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
SRAM_SEQUENTIAL_MODE = const(1 << 6) SRAM_SEQUENTIAL_MODE = const(1 << 6)
class Adafruit_MCP_SRAM_View: class Adafruit_MCP_SRAM_View:
"""An interface class that turns an SRAM chip into something like a memoryview""" """A interface class that turns an SRAM chip into something like a memoryview"""
def __init__(self, sram: int, offset: int) -> None: def __init__(self, sram, offset):
self._sram = sram self._sram = sram
self._offset = offset self._offset = offset
self._buf = [0] self._buf = [0]
def __getitem__(self, i: int) -> Any: def __getitem__(self, i):
return self._sram.read(self._offset + i, 1)[0] return self._sram.read(self._offset + i, 1)[0]
def __setitem__(self, i: int, val: Any) -> None: def __setitem__(self, i, val):
self._buf[0] = val self._buf[0] = val
self._sram.write(self._offset + i, self._buf) self._sram.write(self._offset + i, self._buf)
@ -52,7 +43,7 @@ class Adafruit_MCP_SRAM:
SRAM_RDSR = 0x05 SRAM_RDSR = 0x05
SRAM_WRSR = 0x01 SRAM_WRSR = 0x01
def __init__(self, cs_pin: DigitalInOut, spi: SPI): def __init__(self, cs_pin, spi):
# Handle hardware SPI # Handle hardware SPI
self._spi = spi_device.SPIDevice(spi, cs_pin, baudrate=8000000) self._spi = spi_device.SPIDevice(spi, cs_pin, baudrate=8000000)
self.spi_device = spi self.spi_device = spi
@ -61,23 +52,23 @@ class Adafruit_MCP_SRAM:
self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRSR self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRSR
self._buf[1] = 0x43 self._buf[1] = 0x43
with self._spi as spidev: with self._spi as spidev:
spidev.write(self._buf, end=2) spidev.write(self._buf, end=2) # pylint: disable=no-member
def get_view(self, offset: int) -> Adafruit_MCP_SRAM_View: def get_view(self, offset):
"""Create an object that can be used as a memoryview, with a given offset""" """Create an object that can be used as a memoryview, with a given offset"""
return Adafruit_MCP_SRAM_View(self, offset) return Adafruit_MCP_SRAM_View(self, offset)
def write(self, addr: int, buf: List, reg=SRAM_WRITE): def write(self, addr, buf, reg=SRAM_WRITE):
"""write the passed buffer to the passed address""" """write the passed buffer to the passed address"""
self._buf[0] = reg self._buf[0] = reg
self._buf[1] = (addr >> 8) & 0xFF self._buf[1] = (addr >> 8) & 0xFF
self._buf[2] = addr & 0xFF self._buf[2] = addr & 0xFF
with self._spi as spi: with self._spi as spi:
spi.write(self._buf, end=3) spi.write(self._buf, end=3) # pylint: disable=no-member
spi.write(bytearray(buf)) spi.write(bytearray(buf)) # pylint: disable=no-member
def read(self, addr: int, length: int, reg: int = SRAM_READ): def read(self, addr, length, reg=SRAM_READ):
"""read passed number of bytes at the passed address""" """read passed number of bytes at the passed address"""
self._buf[0] = reg self._buf[0] = reg
self._buf[1] = (addr >> 8) & 0xFF self._buf[1] = (addr >> 8) & 0xFF
@ -85,34 +76,34 @@ class Adafruit_MCP_SRAM:
buf = bytearray(length) buf = bytearray(length)
with self._spi as spi: with self._spi as spi:
spi.write(self._buf, end=3) spi.write(self._buf, end=3) # pylint: disable=no-member
spi.readinto(buf) spi.readinto(buf) # pylint: disable=no-member
return buf return buf
def read8(self, addr: int, reg: int = SRAM_READ): def read8(self, addr, reg=SRAM_READ):
"""read a single byte at the passed address""" """read a single byte at the passed address"""
return self.read(addr, 1, reg)[0] return self.read(addr, 1, reg)[0]
def read16(self, addr: int, reg: int = SRAM_READ): def read16(self, addr, reg=SRAM_READ):
"""read 2 bytes at the passed address""" """read 2 bytes at the passed address"""
buf = self.read(addr, 2, reg) buf = self.read(addr, 2, reg)
return buf[0] << 8 | buf[1] return buf[0] << 8 | buf[1]
def write8(self, addr: int, value: int, reg: int = SRAM_WRITE): def write8(self, addr, value, reg=SRAM_WRITE):
"""write a single byte at the passed address""" """write a single byte at the passed address"""
self.write(addr, [value], reg) self.write(addr, [value], reg)
def write16(self, addr: int, value: int, reg: int = SRAM_WRITE): def write16(self, addr, value, reg=SRAM_WRITE):
"""write 2 bytes at the passed address""" """write 2 bytes at the passed address"""
self.write(addr, [value >> 8, value], reg) self.write(addr, [value >> 8, value], reg)
def erase(self, addr: int, length: int, value: Any): def erase(self, addr, length, value):
"""erase the passed number of bytes starting at the passed address""" """erase the passed number of bytes starting at the passed address"""
self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRITE self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRITE
self._buf[1] = (addr >> 8) & 0xFF self._buf[1] = (addr >> 8) & 0xFF
self._buf[2] = addr & 0xFF self._buf[2] = addr & 0xFF
fill = bytearray([value]) fill = bytearray([value])
with self._spi as spi: with self._spi as spi:
spi.write(self._buf, end=3) spi.write(self._buf, end=3) # pylint: disable=no-member
for _ in range(length): for _ in range(length):
spi.write(fill) spi.write(fill) # pylint: disable=no-member

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit SSD1608 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1608_DRIVER_CONTROL = const(0x01) _SSD1608_DRIVER_CONTROL = const(0x01)
@ -62,27 +49,19 @@ _SSD1608_SET_RAMYPOS = const(0x45)
_SSD1608_SET_RAMXCOUNT = const(0x4E) _SSD1608_SET_RAMXCOUNT = const(0x4E)
_SSD1608_SET_RAMYCOUNT = const(0x4F) _SSD1608_SET_RAMYCOUNT = const(0x4F)
_SSD1608_NOP = const(0xFF) _SSD1608_NOP = const(0xFF)
_LUT_DATA = ( _LUT_DATA = b'\x02\x02\x01\x11\x12\x12""fiiYX\x99\x99\x88\x00\x00\x00\x00\xf8\xb4\x13Q5QQ\x19\x01\x00' # pylint: disable=line-too-long
b'\x02\x02\x01\x11\x12\x12""fiiYX\x99\x99\x88\x00\x00\x00\x00\xf8\xb4\x13Q5QQ\x19\x01\x00' # noqa: E501
)
class Adafruit_SSD1608(Adafruit_EPD): class Adafruit_SSD1608(Adafruit_EPD):
"""driver class for Adafruit SSD1608 ePaper display breakouts""" """driver class for Adafruit SSD1608 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
if height % 8 != 0: if height % 8 != 0:
height += 8 - height % 8 height += 8 - height % 8
@ -101,13 +80,13 @@ class Adafruit_SSD1608(Adafruit_EPD):
self.set_color_buffer(0, True) self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -116,7 +95,7 @@ class Adafruit_SSD1608(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
self.busy_wait() self.busy_wait()
@ -146,12 +125,12 @@ class Adafruit_SSD1608(Adafruit_EPD):
self.command(_SSD1608_WRITE_LUT, _LUT_DATA) self.command(_SSD1608_WRITE_LUT, _LUT_DATA)
self.busy_wait() self.busy_wait()
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_SSD1608_DEEP_SLEEP, bytearray([0x01])) self.command(_SSD1608_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1) time.sleep(0.1)
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_SSD1608_DISP_CTRL2, bytearray([0xC7])) self.command(_SSD1608_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1608_MASTER_ACTIVATE) self.command(_SSD1608_MASTER_ACTIVATE)
@ -159,7 +138,7 @@ class Adafruit_SSD1608(Adafruit_EPD):
if not self._busy: if not self._busy:
time.sleep(3) # wait 3 seconds time.sleep(3) # wait 3 seconds
def write_ram(self, index: Literal[0]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -167,7 +146,7 @@ class Adafruit_SSD1608(Adafruit_EPD):
return self.command(_SSD1608_WRITE_RAM, end=False) return self.command(_SSD1608_WRITE_RAM, end=False)
raise RuntimeError("RAM index must be 0") raise RuntimeError("RAM index must be 0")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
# Set RAM X address counter # Set RAM X address counter

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit SSD1675 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1675_DRIVER_CONTROL = const(0x01) _SSD1675_DRIVER_CONTROL = const(0x01)
@ -56,25 +43,19 @@ _SSD1675_SET_RAMXCOUNT = const(0x4E)
_SSD1675_SET_RAMYCOUNT = const(0x4F) _SSD1675_SET_RAMYCOUNT = const(0x4F)
_SSD1675_SET_ANALOGBLOCK = const(0x74) _SSD1675_SET_ANALOGBLOCK = const(0x74)
_SSD1675_SET_DIGITALBLOCK = const(0x7E) _SSD1675_SET_DIGITALBLOCK = const(0x7E)
_LUT_DATA = b"\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x02\t\t\x00\x00\x02\x03\x03\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa820\n" # noqa: E501 _LUT_DATA = b"\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x02\t\t\x00\x00\x02\x03\x03\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa820\n" # pylint: disable=line-too-long
class Adafruit_SSD1675(Adafruit_EPD): class Adafruit_SSD1675(Adafruit_EPD):
"""driver class for Adafruit SSD1675 ePaper display breakouts""" """driver class for Adafruit SSD1675 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int,
height: int,
spi: SPI,
*,
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
): ):
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin) super().__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
stride = width stride = width
if stride % 8 != 0: if stride % 8 != 0:
stride += 8 - stride % 8 stride += 8 - stride % 8
@ -108,13 +89,13 @@ class Adafruit_SSD1675(Adafruit_EPD):
self.set_color_buffer(0, True) self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -123,7 +104,7 @@ class Adafruit_SSD1675(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
time.sleep(0.1) time.sleep(0.1)
@ -166,20 +147,20 @@ class Adafruit_SSD1675(Adafruit_EPD):
self.busy_wait() self.busy_wait()
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_SSD1675_DEEP_SLEEP, bytearray([0x01])) self.command(_SSD1675_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1) time.sleep(0.1)
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_SSD1675_DISP_CTRL2, bytearray([0xF4])) self.command(_SSD1675_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1675_MASTER_ACTIVATE) self.command(_SSD1675_MASTER_ACTIVATE)
self.busy_wait() self.busy_wait()
if not self._busy: if not self._busy:
time.sleep(3) # wait 3 seconds time.sleep(3) # wait 3 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -189,7 +170,7 @@ class Adafruit_SSD1675(Adafruit_EPD):
return self.command(_SSD1675_WRITE_RAM2, end=False) return self.command(_SSD1675_WRITE_RAM2, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
self.command(_SSD1675_SET_RAMXCOUNT, bytearray([x])) self.command(_SSD1675_SET_RAMXCOUNT, bytearray([x]))

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit SSD1675 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1675B_DRIVER_CONTROL = const(0x01) _SSD1675B_DRIVER_CONTROL = const(0x01)
@ -82,25 +69,19 @@ _SSD1675B_SET_RAMYCOUNT = const(0x4F)
_SSD1675B_SET_ANALOGBLOCK = const(0x74) _SSD1675B_SET_ANALOGBLOCK = const(0x74)
_SSD1675B_SET_DIGITALBLOCK = const(0x7E) _SSD1675B_SET_DIGITALBLOCK = const(0x7E)
_SSD1675B_NOP = const(0xFF) _SSD1675B_NOP = const(0xFF)
_LUT_DATA = b"\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x0f\x00\x00\x00\x0f\x0f\x00\x00\x03\x0f\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa82P,\x0b" # noqa: E501 _LUT_DATA = b"\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x0f\x00\x00\x00\x0f\x0f\x00\x00\x03\x0f\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa82P,\x0b" # pylint: disable=line-too-long
class Adafruit_SSD1675B(Adafruit_EPD): class Adafruit_SSD1675B(Adafruit_EPD):
"""driver class for Adafruit SSD1675B ePaper display breakouts""" """driver class for Adafruit SSD1675B ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
stride = width stride = width
if stride % 8 != 0: if stride % 8 != 0:
stride += 8 - stride % 8 stride += 8 - stride % 8
@ -134,13 +115,13 @@ class Adafruit_SSD1675B(Adafruit_EPD):
self.set_color_buffer(0, True) self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -149,7 +130,7 @@ class Adafruit_SSD1675B(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
time.sleep(0.1) time.sleep(0.1)
@ -208,12 +189,12 @@ class Adafruit_SSD1675B(Adafruit_EPD):
self.busy_wait() self.busy_wait()
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_SSD1675B_DEEP_SLEEP, bytearray([0x01])) self.command(_SSD1675B_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1) time.sleep(0.1)
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_SSD1675B_DISP_CTRL2, bytearray([0xC7])) self.command(_SSD1675B_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1675B_MASTER_ACTIVATE) self.command(_SSD1675B_MASTER_ACTIVATE)
@ -221,7 +202,7 @@ class Adafruit_SSD1675B(Adafruit_EPD):
if not self._busy: if not self._busy:
time.sleep(3) # wait 3 seconds time.sleep(3) # wait 3 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -231,7 +212,7 @@ class Adafruit_SSD1675B(Adafruit_EPD):
return self.command(_SSD1675B_WRITE_RAM2, end=False) return self.command(_SSD1675B_WRITE_RAM2, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
self.command(_SSD1675B_SET_RAMXCOUNT, bytearray([x])) self.command(_SSD1675B_SET_RAMXCOUNT, bytearray([x]))

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit SSD1680 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1680_DRIVER_CONTROL = const(0x01) _SSD1680_DRIVER_CONTROL = const(0x01)
@ -83,19 +70,13 @@ _SSD1680_NOP = const(0xFF)
class Adafruit_SSD1680(Adafruit_EPD): class Adafruit_SSD1680(Adafruit_EPD):
"""driver class for Adafruit SSD1680 ePaper display breakouts""" """driver class for Adafruit SSD1680 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
stride = width stride = width
if stride % 8 != 0: if stride % 8 != 0:
@ -129,13 +110,13 @@ class Adafruit_SSD1680(Adafruit_EPD):
self.set_color_buffer(1, False) self.set_color_buffer(1, False)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -144,7 +125,7 @@ class Adafruit_SSD1680(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
self.busy_wait() self.busy_wait()
@ -153,7 +134,7 @@ class Adafruit_SSD1680(Adafruit_EPD):
# driver output control # driver output control
self.command( self.command(
_SSD1680_DRIVER_CONTROL, _SSD1680_DRIVER_CONTROL,
bytearray([(self._height - 1) & 0xFF, (self._height - 1) >> 8, 0x00]), bytearray([self._height - 1, (self._height - 1) >> 8, 0x00]),
) )
# data entry mode # data entry mode
self.command(_SSD1680_DATA_MODE, bytearray([0x03])) self.command(_SSD1680_DATA_MODE, bytearray([0x03]))
@ -163,31 +144,28 @@ class Adafruit_SSD1680(Adafruit_EPD):
self.command(_SSD1680_GATE_VOLTAGE, bytearray([0x17])) self.command(_SSD1680_GATE_VOLTAGE, bytearray([0x17]))
self.command(_SSD1680_SOURCE_VOLTAGE, bytearray([0x41, 0x00, 0x32])) self.command(_SSD1680_SOURCE_VOLTAGE, bytearray([0x41, 0x00, 0x32]))
height = self._width
if height % 8 != 0:
height += 8 - (height % 8)
# Set ram X start/end postion # Set ram X start/end postion
self.command(_SSD1680_SET_RAMXPOS, bytearray([0x00, (height // 8) - 1])) self.command(_SSD1680_SET_RAMXPOS, bytearray([0x01, 0x10]))
# Set ram Y start/end postion # Set ram Y start/end postion
self.command( self.command(
_SSD1680_SET_RAMYPOS, _SSD1680_SET_RAMYPOS,
bytearray([0x00, 0x00, (self._height - 1) & 0xFF, (self._height - 1) >> 8]), bytearray([0, 0, self._height - 1, (self._height - 1) >> 8]),
) )
# Set border waveform # Set border waveform
self.command(_SSD1680_WRITE_BORDER, bytearray([0x05])) self.command(_SSD1680_WRITE_BORDER, bytearray([0x05]))
# Set ram X count # Set ram X count
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([0x00])) self.command(_SSD1680_SET_RAMXCOUNT, bytearray([0x01]))
# Set ram Y count # Set ram Y count
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([0x00, 0x00])) self.command(_SSD1680_SET_RAMYCOUNT, bytearray([self._height - 1, 0]))
self.busy_wait() self.busy_wait()
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_SSD1680_DEEP_SLEEP, bytearray([0x01])) self.command(_SSD1680_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1) time.sleep(0.1)
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_SSD1680_DISP_CTRL2, bytearray([0xF4])) self.command(_SSD1680_DISP_CTRL2, bytearray([0xF4]))
self.command(_SSD1680_MASTER_ACTIVATE) self.command(_SSD1680_MASTER_ACTIVATE)
@ -195,7 +173,7 @@ class Adafruit_SSD1680(Adafruit_EPD):
if not self._busy: if not self._busy:
time.sleep(3) # wait 3 seconds time.sleep(3) # wait 3 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -205,79 +183,10 @@ class Adafruit_SSD1680(Adafruit_EPD):
return self.command(_SSD1680_WRITE_REDRAM, end=False) return self.command(_SSD1680_WRITE_REDRAM, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
# Set RAM X address counter # Set RAM X address counter
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([0])) self.command(_SSD1680_SET_RAMXCOUNT, bytearray([x + 1]))
# Set RAM Y address counter
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([0, 0]))
class Adafruit_SSD1680Z(Adafruit_SSD1680):
"""Driver for SSD1680Z ePaper display, overriding SSD1680 settings."""
def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin):
# Call the parent class's __init__() to initialize attributes
super().__init__(
width,
height,
spi,
cs_pin=cs_pin,
dc_pin=dc_pin,
sramcs_pin=sramcs_pin,
rst_pin=rst_pin,
busy_pin=busy_pin,
)
self.busy_pin = busy_pin # Ensure busy_pin is set
# pylint: enable=too-many-arguments, useless-parent-delegation
def power_up(self):
"""Power up sequence specifically for SSD1680Z."""
self.hardware_reset()
self.busy_wait()
self.command(_SSD1680_SW_RESET)
self.busy_wait()
self.command(
_SSD1680_DRIVER_CONTROL,
bytearray([self._height & 0xFF, (self._height) >> 8, 0x00]),
)
self.command(_SSD1680_DATA_MODE, bytearray([0x03]))
# Set voltages
self.command(_SSD1680_WRITE_VCOM_REG, bytearray([0x36]))
self.command(_SSD1680_GATE_VOLTAGE, bytearray([0x17]))
self.command(_SSD1680_SOURCE_VOLTAGE, bytearray([0x41, 0x00, 0x32]))
self.command(_SSD1680_SET_RAMXPOS, bytearray([0x00, (self._width // 8) - 1]))
self.command(
_SSD1680_SET_RAMYPOS,
bytearray([0x00, 0x00, (self._height - 1) & 0xFF, (self._height - 1) >> 8]),
)
# Set border waveform
self.command(_SSD1680_WRITE_BORDER, bytearray([0x05]))
# Set ram X count
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([0x00]))
# Set ram Y count
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([0x00, 0x00]))
self.busy_wait()
def update(self):
"""Update the display specifically for SSD1680Z."""
self.command(_SSD1680_DISP_CTRL2, bytearray([0xF7])) # Full update for SSD1680Z
self.command(_SSD1680_MASTER_ACTIVATE)
self.busy_wait()
if not self.busy_pin:
time.sleep(3) # Wait for update to complete
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
# Set RAM X address counter
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([x]))
# Set RAM Y address counter # Set RAM Y address counter
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([y, y >> 8])) self.command(_SSD1680_SET_RAMYCOUNT, bytearray([y, y >> 8]))

View file

@ -10,23 +10,11 @@ CircuitPython driver for Adafruit SSD1681 display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1681_DRIVER_CONTROL = const(0x01) _SSD1681_DRIVER_CONTROL = const(0x01)
@ -82,19 +70,13 @@ _SSD1681_NOP = const(0xFF)
class Adafruit_SSD1681(Adafruit_EPD): class Adafruit_SSD1681(Adafruit_EPD):
"""driver class for Adafruit SSD1681 ePaper display breakouts""" """driver class for Adafruit SSD1681 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
if height % 8 != 0: if height % 8 != 0:
height += 8 - height % 8 height += 8 - height % 8
@ -119,13 +101,13 @@ class Adafruit_SSD1681(Adafruit_EPD):
self.set_color_buffer(1, False) self.set_color_buffer(1, False)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -134,7 +116,7 @@ class Adafruit_SSD1681(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
self.busy_wait() self.busy_wait()
@ -143,7 +125,7 @@ class Adafruit_SSD1681(Adafruit_EPD):
# driver output control # driver output control
self.command( self.command(
_SSD1681_DRIVER_CONTROL, _SSD1681_DRIVER_CONTROL,
bytearray([(self._width - 1) & 0xFF, (self._width - 1) >> 8, 0x00]), bytearray([self._width - 1, (self._width - 1) >> 8, 0x00]),
) )
# data entry mode # data entry mode
self.command(_SSD1681_DATA_MODE, bytearray([0x03])) self.command(_SSD1681_DATA_MODE, bytearray([0x03]))
@ -152,7 +134,7 @@ class Adafruit_SSD1681(Adafruit_EPD):
# Set ram Y start/end postion # Set ram Y start/end postion
self.command( self.command(
_SSD1681_SET_RAMYPOS, _SSD1681_SET_RAMYPOS,
bytearray([0, 0, (self._height - 1) & 0xFF, (self._height - 1) >> 8]), bytearray([0, 0, self._height - 1, (self._height - 1) >> 8]),
) )
# Set border waveform # Set border waveform
self.command(_SSD1681_WRITE_BORDER, bytearray([0x05])) self.command(_SSD1681_WRITE_BORDER, bytearray([0x05]))
@ -161,12 +143,12 @@ class Adafruit_SSD1681(Adafruit_EPD):
self.busy_wait() self.busy_wait()
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_SSD1681_DEEP_SLEEP, bytearray([0x01])) self.command(_SSD1681_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1) time.sleep(0.1)
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_SSD1681_DISP_CTRL2, bytearray([0xF7])) self.command(_SSD1681_DISP_CTRL2, bytearray([0xF7]))
self.command(_SSD1681_MASTER_ACTIVATE) self.command(_SSD1681_MASTER_ACTIVATE)
@ -174,7 +156,7 @@ class Adafruit_SSD1681(Adafruit_EPD):
if not self._busy: if not self._busy:
time.sleep(3) # wait 3 seconds time.sleep(3) # wait 3 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -184,10 +166,10 @@ class Adafruit_SSD1681(Adafruit_EPD):
return self.command(_SSD1681_WRITE_REDRAM, end=False) return self.command(_SSD1681_WRITE_REDRAM, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
# Set RAM X address counter # Set RAM X address counter
self.command(_SSD1681_SET_RAMXCOUNT, bytearray([x])) self.command(_SSD1681_SET_RAMXCOUNT, bytearray([x]))
# Set RAM Y address counter # Set RAM Y address counter
self.command(_SSD1681_SET_RAMYCOUNT, bytearray([y & 0xFF, y >> 8])) self.command(_SSD1681_SET_RAMYCOUNT, bytearray([y, y >> 8]))

View file

@ -1,262 +0,0 @@
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_epd.ssd1683` - Adafruit SSD1683 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1683 display breakouts
* Author(s): Liz Clark
"""
import time
import adafruit_framebuf
from micropython import const
from adafruit_epd.epd import Adafruit_EPD
try:
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
# Command constants
_SSD1683_DRIVER_CONTROL = const(0x01)
_SSD1683_GATE_VOLTAGE = const(0x03)
_SSD1683_SOURCE_VOLTAGE = const(0x04)
_SSD1683_PROGOTP_INITIAL = const(0x08)
_SSD1683_PROGREG_INITIAL = const(0x09)
_SSD1683_READREG_INITIAL = const(0x0A)
_SSD1683_BOOST_SOFTSTART = const(0x0C)
_SSD1683_DEEP_SLEEP = const(0x10)
_SSD1683_DATA_MODE = const(0x11)
_SSD1683_SW_RESET = const(0x12)
_SSD1683_HV_READY = const(0x14)
_SSD1683_VCI_DETECT = const(0x15)
_SSD1683_PROGRAM_WSOTP = const(0x16)
_SSD1683_PROGRAM_AUTO = const(0x17)
_SSD1683_TEMP_CONTROL = const(0x18)
_SSD1683_TEMP_WRITE = const(0x1A)
_SSD1683_TEMP_READ = const(0x1B)
_SSD1683_TEMP_CONTROLEXT = const(0x1C)
_SSD1683_MASTER_ACTIVATE = const(0x20)
_SSD1683_DISP_CTRL1 = const(0x21)
_SSD1683_DISP_CTRL2 = const(0x22)
_SSD1683_WRITE_RAM1 = const(0x24)
_SSD1683_WRITE_RAM2 = const(0x26)
_SSD1683_READ_RAM1 = const(0x27)
_SSD1683_SENSE_VCOM = const(0x28)
_SSD1683_SENSEDUR_VCOM = const(0x29)
_SSD1683_PROGOTP_VCOM = const(0x2A)
_SSD1683_WRITE_VCOM = const(0x2C)
_SSD1683_READ_OTP = const(0x2D)
_SSD1683_READ_USERID = const(0x2E)
_SSD1683_READ_STATUS = const(0x2F)
_SSD1683_WRITE_LUT = const(0x32)
_SSD1683_WRITE_BORDER = const(0x3C)
_SSD1683_END_OPTION = const(0x3F)
_SSD1683_SET_RAMXPOS = const(0x44)
_SSD1683_SET_RAMYPOS = const(0x45)
_SSD1683_SET_RAMXCOUNT = const(0x4E)
_SSD1683_SET_RAMYCOUNT = const(0x4F)
# Other constants
_EPD_RAM_BW = const(0x10)
_EPD_RAM_RED = const(0x13)
_BUSY_WAIT = const(500)
class Adafruit_SSD1683(Adafruit_EPD):
"""driver class for Adafruit SSD1683 ePaper display breakouts"""
def __init__(
self,
width: int,
height: int,
spi: SPI,
*,
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
stride = width
if stride % 8 != 0:
stride += 8 - stride % 8
self._buffer1_size = int(stride * height / 8)
self._buffer2_size = self._buffer1_size
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray(self._buffer1_size)
self._buffer2 = bytearray(self._buffer2_size)
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB
)
self.set_black_buffer(0, True)
self.set_color_buffer(1, False)
# Set single byte transactions flag
self._single_byte_tx = True
# Set the display update value
self._display_update_val = 0xF7
# Default initialization sequence (tri-color mode)
self._default_init_code = bytes(
[
_SSD1683_SW_RESET,
0, # Software reset
0xFF,
50, # Wait for busy (50ms delay)
_SSD1683_WRITE_BORDER,
1, # Border waveform control
0x05, # Border color/waveform
_SSD1683_TEMP_CONTROL,
1, # Temperature control
0x80, # Read temp
_SSD1683_DATA_MODE,
1, # Data entry mode
0x03, # Y decrement, X increment
0xFE, # End of initialization
]
)
def begin(self, reset: bool = True) -> None:
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self) -> None:
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while self._busy.value: # wait for busy low
time.sleep(0.01)
else:
time.sleep(_BUSY_WAIT / 1000.0) # Convert ms to seconds
def power_up(self) -> None:
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
time.sleep(0.1)
self.busy_wait()
# Use custom init code if provided, otherwise use default
init_code = self._default_init_code
if hasattr(self, "_epd_init_code") and self._epd_init_code is not None:
init_code = self._epd_init_code
# Send initialization sequence
self._send_command_list(init_code)
# Set RAM window
self.set_ram_window(0, 0, (self._width // 8) - 1, self._height - 1)
# Set RAM address to start position
self.set_ram_address(0, 0)
# Set LUT if we have one
if hasattr(self, "_epd_lut_code") and self._epd_lut_code:
self._send_command_list(self._epd_lut_code)
# Set display size and driver output control
_b0 = (self._height - 1) & 0xFF
_b1 = ((self._height - 1) >> 8) & 0xFF
_b2 = 0x00
self.command(_SSD1683_DRIVER_CONTROL, bytearray([_b0, _b1, _b2]))
def power_down(self) -> None:
"""Power down the display - required when not actively displaying!"""
# Only deep sleep if we can get out of it
if self._rst:
# deep sleep
self.command(_SSD1683_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1)
else:
self.command(_SSD1683_SW_RESET)
self.busy_wait()
def update(self) -> None:
"""Update the display from internal memory"""
# display update sequence
self.command(_SSD1683_DISP_CTRL2, bytearray([self._display_update_val]))
self.command(_SSD1683_MASTER_ACTIVATE)
self.busy_wait()
if not self._busy:
time.sleep(1) # wait 1 second
def write_ram(self, index: Literal[0, 1]) -> int:
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_SSD1683_WRITE_RAM1, end=False)
if index == 1:
return self.command(_SSD1683_WRITE_RAM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None:
"""Set the RAM address location"""
# set RAM x address count
self.command(_SSD1683_SET_RAMXCOUNT, bytearray([x & 0xFF]))
# set RAM y address count
self.command(_SSD1683_SET_RAMYCOUNT, bytearray([y & 0xFF, (y >> 8) & 0xFF]))
def set_ram_window(self, x1: int, y1: int, x2: int, y2: int) -> None:
"""Set the RAM window for partial updates"""
# Set ram X start/end position
self.command(_SSD1683_SET_RAMXPOS, bytearray([x1 & 0xFF, x2 & 0xFF]))
# Set ram Y start/end position
self.command(
_SSD1683_SET_RAMYPOS,
bytearray([y1 & 0xFF, (y1 >> 8) & 0xFF, y2 & 0xFF, (y2 >> 8) & 0xFF]),
)
def _send_command_list(self, init_sequence: bytes) -> None:
"""Send a sequence of commands from an initialization list"""
i = 0
while i < len(init_sequence):
cmd = init_sequence[i]
i += 1
if cmd == 0xFE: # End marker
break
elif cmd == 0xFF: # Delay marker
if i < len(init_sequence):
delay_ms = init_sequence[i]
i += 1
time.sleep(delay_ms / 1000.0)
elif i < len(init_sequence):
num_args = init_sequence[i]
i += 1
if num_args > 0 and (i + num_args) <= len(init_sequence):
args = init_sequence[i : i + num_args]
self.command(cmd, bytearray(args))
i += num_args
else:
self.command(cmd)

View file

@ -10,24 +10,11 @@ CircuitPython driver for Adafruit UC8151D display breakouts
""" """
import time import time
import adafruit_framebuf
from micropython import const from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
try: __version__ = "0.0.0-auto.0"
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_UC8151D_PANEL_SETTING = const(0x00) _UC8151D_PANEL_SETTING = const(0x00)
@ -74,19 +61,13 @@ _UC8151D_TSSET = const(0xE5)
class Adafruit_UC8151D(Adafruit_EPD): class Adafruit_UC8151D(Adafruit_EPD):
"""driver class for Adafruit UC8151D ePaper display breakouts""" """driver class for Adafruit UC8151D ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__( def __init__(
self, self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
width: int, ):
height: int, super().__init__(
spi: SPI, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
*, )
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
self._buffer1_size = int(width * height / 8) self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8) self._buffer2_size = int(width * height / 8)
@ -109,13 +90,13 @@ class Adafruit_UC8151D(Adafruit_EPD):
self.set_color_buffer(1, True) self.set_color_buffer(1, True)
# pylint: enable=too-many-arguments # pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None: def begin(self, reset=True):
"""Begin communication with the display and set basic settings""" """Begin communication with the display and set basic settings"""
if reset: if reset:
self.hardware_reset() self.hardware_reset()
self.power_down() self.power_down()
def busy_wait(self) -> None: def busy_wait(self):
"""Wait for display to be done with current task, either by polling the """Wait for display to be done with current task, either by polling the
busy pin, or pausing""" busy pin, or pausing"""
if self._busy: if self._busy:
@ -124,7 +105,7 @@ class Adafruit_UC8151D(Adafruit_EPD):
else: else:
time.sleep(0.5) time.sleep(0.5)
def power_up(self) -> None: def power_up(self):
"""Power up the display in preparation for writing RAM and updating""" """Power up the display in preparation for writing RAM and updating"""
self.hardware_reset() self.hardware_reset()
self.busy_wait() self.busy_wait()
@ -138,14 +119,14 @@ class Adafruit_UC8151D(Adafruit_EPD):
self.command(_UC8151D_CDI, bytearray([0x97])) self.command(_UC8151D_CDI, bytearray([0x97]))
time.sleep(0.05) time.sleep(0.05)
def power_down(self) -> None: def power_down(self):
"""Power down the display - required when not actively displaying!""" """Power down the display - required when not actively displaying!"""
self.command(_UC8151D_CDI, bytearray([0xF7])) self.command(_UC8151D_CDI, bytearray([0xF7]))
self.command(_UC8151D_POWER_OFF) self.command(_UC8151D_POWER_OFF)
self.busy_wait() self.busy_wait()
self.command(_UC8151D_DEEP_SLEEP, bytearray([0xA5])) self.command(_UC8151D_DEEP_SLEEP, bytearray([0xA5]))
def update(self) -> None: def update(self):
"""Update the display from internal memory""" """Update the display from internal memory"""
self.command(_UC8151D_DISPLAY_REFRESH) self.command(_UC8151D_DISPLAY_REFRESH)
time.sleep(0.1) time.sleep(0.1)
@ -153,7 +134,7 @@ class Adafruit_UC8151D(Adafruit_EPD):
if not self._busy: if not self._busy:
time.sleep(15) # wait 15 seconds time.sleep(15) # wait 15 seconds
def write_ram(self, index: Literal[0, 1]) -> int: def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns """Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays.""" 0 or 1 for tri-color displays."""
@ -163,7 +144,7 @@ class Adafruit_UC8151D(Adafruit_EPD):
return self.command(_UC8151D_DTM2, end=False) return self.command(_UC8151D_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1") raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by """Set the RAM address location, not used on this chipset but required by
the superclass""" the superclass"""
return # on this chip it does nothing return # on this chip it does nothing

View file

@ -1,213 +0,0 @@
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_epd.uc8179` - Adafruit UC8179 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit UC8179 display breakouts
* Author(s): Liz Clark
"""
import time
import adafruit_framebuf
from micropython import const
from adafruit_epd.epd import Adafruit_EPD
try:
"""Needed for type annotations"""
import typing
from busio import SPI
from digitalio import DigitalInOut
from typing_extensions import Literal
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
# UC8179 commands
_UC8179_PANELSETTING = const(0x00)
_UC8179_POWERSETTING = const(0x01)
_UC8179_POWEROFF = const(0x02)
_UC8179_POWERON = const(0x04)
_UC8179_DEEPSLEEP = const(0x07)
_UC8179_WRITE_RAM1 = const(0x10)
_UC8179_DATASTOP = const(0x11)
_UC8179_DISPLAYREFRESH = const(0x12)
_UC8179_WRITE_RAM2 = const(0x13)
_UC8179_DUALSPI = const(0x15)
_UC8179_WRITE_VCOM = const(0x50)
_UC8179_TCON = const(0x60)
_UC8179_TRES = const(0x61)
_UC8179_GET_STATUS = const(0x71)
BUSY_WAIT = const(500) # milliseconds
class Adafruit_UC8179(Adafruit_EPD):
"""driver class for Adafruit UC8179 ePaper display breakouts"""
def __init__(
self,
width: int,
height: int,
spi: SPI,
*,
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
# Adjust height to be divisible by 8 (direct from Arduino)
if (height % 8) != 0:
height += 8 - (height % 8)
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
# Calculate buffer sizes exactly as Arduino does: width * height / 8
self._buffer1_size = width * height // 8
self._buffer2_size = self._buffer1_size
if sramcs_pin:
# Using external SRAM
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
# Using internal RAM
self._buffer1 = bytearray(self._buffer1_size)
self._buffer2 = bytearray(self._buffer2_size)
# Create frame buffers
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1,
width,
height,
buf_format=adafruit_framebuf.MHMSB,
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2,
width,
height,
buf_format=adafruit_framebuf.MHMSB,
)
# Set up which frame buffer is which color
self.set_black_buffer(0, True)
self.set_color_buffer(1, False)
# UC8179 uses single byte transactions
self._single_byte_tx = False
# Default refresh delay (from Adafruit_EPD base class in Arduino)
self.default_refresh_delay = 15 # seconds
# pylint: enable=too-many-arguments
def begin(self, reset: bool = True) -> None:
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self) -> None:
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
# Wait for busy pin to go HIGH
while not self._busy.value:
self.command(_UC8179_GET_STATUS)
time.sleep(0.1)
else:
# No busy pin, just wait
time.sleep(BUSY_WAIT / 1000.0)
# Additional delay after busy signal
time.sleep(0.2)
def power_up(self) -> None:
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
# Power setting
self.command(
_UC8179_POWERSETTING,
bytearray(
[
0x07, # VGH=20V
0x07, # VGL=-20V
0x3F, # VDH=15V
0x3F, # VDL=-15V
]
),
)
# Power on
self.command(_UC8179_POWERON)
time.sleep(0.1) # 100ms delay
self.busy_wait()
# Panel setting
self.command(_UC8179_PANELSETTING, bytearray([0b011111])) # BW OTP LUT
# Resolution setting
self.command(
_UC8179_TRES,
bytearray(
[self._width >> 8, self._width & 0xFF, self._height >> 8, self._height & 0xFF]
),
)
# Dual SPI setting
self.command(_UC8179_DUALSPI, bytearray([0x00]))
# VCOM setting
self.command(_UC8179_WRITE_VCOM, bytearray([0x10, 0x07]))
# TCON setting
self.command(_UC8179_TCON, bytearray([0x22]))
def power_down(self) -> None:
"""Power down the display - required when not actively displaying!"""
self.command(_UC8179_POWEROFF)
self.busy_wait()
# Only deep sleep if we have a reset pin to wake it up
if self._rst:
self.command(_UC8179_DEEPSLEEP, bytearray([0x05]))
time.sleep(0.1)
def update(self) -> None:
"""Update the display from internal memory"""
self.command(_UC8179_DISPLAYREFRESH)
time.sleep(0.1) # 100ms delay
self.busy_wait()
if not self._busy:
# If no busy pin, use default refresh delay
time.sleep(self.default_refresh_delay)
def write_ram(self, index: Literal[0, 1]) -> int:
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_UC8179_WRITE_RAM1, end=False)
if index == 1:
return self.command(_UC8179_WRITE_RAM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x: int, y: int) -> None: # noqa: PLR6301, F841
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
# Not used in UC8179 chip
pass
def set_ram_window(self, x1: int, y1: int, x2: int, y2: int) -> None: # noqa: PLR6301, F841
"""Set the RAM window, not used on this chipset but required by
the superclass"""
# Not used in UC8179 chip
pass

View file

@ -4,8 +4,5 @@
.. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py)
.. use this format as the module name: "adafruit_foo.foo" .. use this format as the module name: "adafruit_foo.foo"
API Reference
#############
.. automodule:: adafruit_epd.epd .. automodule:: adafruit_epd.epd
:members: :members:

View file

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import datetime
import os import os
import sys import sys
@ -15,7 +16,6 @@ sys.path.insert(0, os.path.abspath(".."))
# ones. # ones.
extensions = [ extensions = [
"sphinx.ext.autodoc", "sphinx.ext.autodoc",
"sphinxcontrib.jquery",
"sphinx.ext.intersphinx", "sphinx.ext.intersphinx",
"sphinx.ext.napoleon", "sphinx.ext.napoleon",
"sphinx.ext.todo", "sphinx.ext.todo",
@ -28,16 +28,16 @@ extensions = [
intersphinx_mapping = { intersphinx_mapping = {
"python": ("https://docs.python.org/3", None), "python": ("https://docs.python.org/3.4", None),
"BusDevice": ( "BusDevice": (
"https://docs.circuitpython.org/projects/busdevice/en/latest/", "https://circuitpython.readthedocs.io/projects/busdevice/en/latest/",
None, None,
), ),
"Register": ( "Register": (
"https://docs.circuitpython.org/projects/register/en/latest/", "https://circuitpython.readthedocs.io/projects/register/en/latest/",
None, None,
), ),
"CircuitPython": ("https://docs.circuitpython.org/en/latest/", None), "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
} }
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
@ -50,12 +50,7 @@ master_doc = "index"
# General information about the project. # General information about the project.
project = "Adafruit EPD Library" project = "Adafruit EPD Library"
creation_year = "2018" copyright = "2018 Dean Miller"
current_year = str(datetime.datetime.now().year)
year_duration = (
current_year if current_year == creation_year else creation_year + " - " + current_year
)
copyright = year_duration + " Dean Miller"
author = "Dean Miller" author = "Dean Miller"
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
@ -72,7 +67,7 @@ release = "1.0"
# #
# This is also used if you do content translation via gettext catalogs. # This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases. # Usually you set "language" from the command line for these cases.
language = "en" language = None
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
@ -104,9 +99,19 @@ napoleon_numpy_docstring = False
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
# #
import sphinx_rtd_theme on_rtd = os.environ.get("READTHEDOCS", None) == "True"
html_theme = "sphinx_rtd_theme" if not on_rtd: # only import and set the theme if we're building docs locally
try:
import sphinx_rtd_theme
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
except:
html_theme = "default"
html_theme_path = ["."]
else:
html_theme_path = ["."]
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,

View file

@ -31,9 +31,8 @@ Table of Contents
.. toctree:: .. toctree::
:caption: Other Links :caption: Other Links
Download from GitHub <https://github.com/adafruit/Adafruit_CircuitPython_EPD/releases/latest> Download <https://github.com/adafruit/Adafruit_CircuitPython_EPD/releases/latest>
Download Library Bundle <https://circuitpython.org/libraries> CircuitPython Reference Documentation <https://circuitpython.readthedocs.io>
CircuitPython Reference Documentation <https://docs.circuitpython.org>
CircuitPython Support Forum <https://forums.adafruit.com/viewforum.php?f=60> CircuitPython Support Forum <https://forums.adafruit.com/viewforum.php?f=60>
Discord Chat <https://adafru.it/discord> Discord Chat <https://adafru.it/discord>
Adafruit Learning System <https://learn.adafruit.com> Adafruit Learning System <https://learn.adafruit.com>

View file

@ -1,7 +0,0 @@
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
sphinx
sphinxcontrib-jquery
sphinx-rtd-theme

View file

@ -1,22 +1,19 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import board
import busio
import digitalio import digitalio
import busio
from adafruit_epd.ek79686 import Adafruit_EK79686 import board
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373 from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il0398 import Adafruit_IL0398 from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il91874 import Adafruit_IL91874 from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680 from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.ssd1683 import Adafruit_SSD1683 from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.uc8151d import Adafruit_UC8151D
from adafruit_epd.uc8179 import Adafruit_UC8179
# create the spi device and pins we will need # create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
@ -33,14 +30,9 @@ print("Creating display")
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display # display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display # display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display # display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display # display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display
# display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display # display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display
# display = Adafruit_UC8179(648, 480, # 5.83" mono 648x480 display # display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display
# display = Adafruit_UC8179(800, 480, # 7.5" mono 800x480 display
# display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display IL0373
# display = Adafruit_SSD1680(128, 296, # 2.9" Tri-color display SSD1680
# display = Adafruit_SSD1683(400, 300, # 4.2" 300x400 Tri-Color display
# display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display # display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display
display = Adafruit_IL0373( display = Adafruit_IL0373(
104, 104,
@ -53,9 +45,7 @@ display = Adafruit_IL0373(
busy_pin=busy, busy_pin=busy,
) )
# IF YOU HAVE A 2.13" FLEXIBLE DISPLAY OR! # IF YOU HAVE A 2.13" FLEXIBLE DISPLAY uncomment these lines!
# UC8179 5.83" or 7.5" displays
# uncomment these lines!
# display.set_black_buffer(1, False) # display.set_black_buffer(1, False)
# display.set_color_buffer(1, False) # display.set_color_buffer(1, False)
@ -82,9 +72,9 @@ class BMPError(Exception):
pass pass
def display_bitmap(epd, filename): def display_bitmap(epd, filename): # pylint: disable=too-many-locals, too-many-branches
try: try:
f = open(filename, "rb") f = open(filename, "rb") # pylint: disable=consider-using-with
except OSError: except OSError:
print("Couldn't open file") print("Couldn't open file")
return return

View file

@ -1,25 +1,26 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import board
import busio
import digitalio import digitalio
from PIL import Image, ImageDraw, ImageFont import busio
import board
from adafruit_epd.ek79686 import Adafruit_EK79686 from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373 from adafruit_epd.il0373 import Adafruit_IL0373 # pylint: disable=unused-import
from adafruit_epd.il0398 import Adafruit_IL0398 from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il91874 import Adafruit_IL91874 from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.jd79661 import Adafruit_JD79661 from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 from adafruit_epd.ssd1675b import Adafruit_SSD1675B # pylint: disable=unused-import
from adafruit_epd.ssd1675b import Adafruit_SSD1675B from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680 from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ssd1683 import Adafruit_SSD1683
from adafruit_epd.uc8151d import Adafruit_UC8151D # create the spi device and pins we will need
from adafruit_epd.uc8179 import Adafruit_UC8179 spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
# create the spi device and pins we will need # create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
@ -32,18 +33,13 @@ busy = digitalio.DigitalInOut(board.D7) # can be None to not use this pin
# give them all to our driver # give them all to our driver
print("Creating display") print("Creating display")
# display = Adafruit_JD79661(122, 150, # 2.13" Quad-color display
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display # display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display # display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display # display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display # display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_SSD1683(400, 300, # 4.2" 300x400 Tri-Color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display # display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display # display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display
# display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display # display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display
# display = Adafruit_UC8179(648, 480, # 5.83" mono 648x480 display
# display = Adafruit_UC8179(800, 480, # 7.5" mono 800x480 display
# display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display # display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display
# display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display # display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display
# display = Adafruit_IL0373(104, 212, # 2.13" Tri-color display # display = Adafruit_IL0373(104, 212, # 2.13" Tri-color display
@ -58,9 +54,7 @@ display = Adafruit_SSD1675B(
busy_pin=busy, busy_pin=busy,
) )
# IF YOU HAVE A 2.13" FLEXIBLE DISPLAY OR! # IF YOU HAVE A 2.13" FLEXIBLE DISPLAY uncomment these lines!
# UC8179 5.83" or 7.5" displays
# uncomment these lines!
# display.set_black_buffer(1, False) # display.set_black_buffer(1, False)
# display.set_color_buffer(1, False) # display.set_color_buffer(1, False)
@ -76,7 +70,6 @@ height = display.height
image = Image.new("RGB", (width, height)) image = Image.new("RGB", (width, height))
WHITE = (0xFF, 0xFF, 0xFF) WHITE = (0xFF, 0xFF, 0xFF)
YELLOW = (0xFF, 0xFF, 0x00)
RED = (0xFF, 0x00, 0x00) RED = (0xFF, 0x00, 0x00)
BLACK = (0x00, 0x00, 0x00) BLACK = (0x00, 0x00, 0x00)
@ -125,15 +118,9 @@ font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
# Some other nice fonts to try: http://www.dafont.com/bitmap.php # Some other nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8) # font = ImageFont.truetype('Minecraftia.ttf', 8)
if type(display) == Adafruit_JD79661:
# for quad color, test yellow
fill = YELLOW
else:
# otherwise, text is red
fill = RED
# Write two lines of text. # Write two lines of text.
draw.text((x, top), "Hello", font=font, fill=fill) draw.text((x, top), "Hello", font=font, fill=RED)
draw.text((x, top + 20), "World!", font=font, fill=fill) draw.text((x, top + 20), "World!", font=font, fill=RED)
# Display image. # Display image.
display.image(image) display.image(image)

View file

@ -2,15 +2,15 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import time import time
import board
import busio import busio
import board
from digitalio import DigitalInOut, Direction from digitalio import DigitalInOut, Direction
from PIL import Image, ImageDraw, ImageFont
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.ssd1675b import Adafruit_SSD1675B from adafruit_epd.ssd1675b import Adafruit_SSD1675B # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680, Adafruit_SSD1680Z
# create two buttons # create two buttons
switch1 = DigitalInOut(board.D6) switch1 = DigitalInOut(board.D6)
@ -26,9 +26,7 @@ rst = DigitalInOut(board.D27)
busy = DigitalInOut(board.D17) busy = DigitalInOut(board.D17)
# give them all to our driver # give them all to our driver
# display = Adafruit_SSD1675B( # Oldest 2.13" Bonnet display = Adafruit_SSD1675B(
# display = Adafruit_SSD1680( # Old 2.13" Bonnet
display = Adafruit_SSD1680Z( # Newer 2.13" mono display
122, 122,
250, 250,
spi, # 2.13" HD mono display (rev B) spi, # 2.13" HD mono display (rev B)
@ -63,29 +61,29 @@ draw.rectangle((0, 0, width, height), fill=WHITE)
draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE)
# Draw some shapes. # Draw some shapes.
# First define some constants to allow easy resizing of shapes. # First define some constants to allow easy resizing of shapes.
PADDING = 5 padding = 5
SHAPE_WIDTH = 30 shape_width = 30
TOP = PADDING top = padding
bottom = height - PADDING bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes. # Move left to right keeping track of the current x position for drawing shapes.
x = PADDING x = padding
# Draw an ellipse. # Draw an ellipse.
draw.ellipse((x, TOP, x + SHAPE_WIDTH, bottom), outline=BLACK, fill=WHITE) draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE)
x += SHAPE_WIDTH + PADDING x += shape_width + padding
# Draw a rectangle. # Draw a rectangle.
draw.rectangle((x, TOP, x + SHAPE_WIDTH, bottom), outline=WHITE, fill=BLACK) draw.rectangle((x, top, x + shape_width, bottom), outline=WHITE, fill=BLACK)
x += SHAPE_WIDTH + PADDING x += shape_width + padding
# Draw a triangle. # Draw a triangle.
draw.polygon( draw.polygon(
[(x, bottom), (x + SHAPE_WIDTH / 2, TOP), (x + SHAPE_WIDTH, bottom)], [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)],
outline=BLACK, outline=BLACK,
fill=WHITE, fill=WHITE,
) )
x += SHAPE_WIDTH + PADDING x += shape_width + padding
# Draw an X. # Draw an X.
draw.line((x, bottom, x + SHAPE_WIDTH, TOP), fill=BLACK) draw.line((x, bottom, x + shape_width, top), fill=BLACK)
draw.line((x, TOP, x + SHAPE_WIDTH, bottom), fill=BLACK) draw.line((x, top, x + shape_width, bottom), fill=BLACK)
x += SHAPE_WIDTH + PADDING x += shape_width + padding
# Load default font. # Load default font.
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20) font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
@ -96,8 +94,8 @@ font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
# font = ImageFont.truetype('Minecraftia.ttf', 8) # font = ImageFont.truetype('Minecraftia.ttf', 8)
# Write two lines of text. # Write two lines of text.
draw.text((x, TOP), "Hello", font=font, fill=BLACK) draw.text((x, top), "Hello", font=font, fill=BLACK)
draw.text((x, TOP + 20), "World!", font=font, fill=BLACK) draw.text((x, top + 20), "World!", font=font, fill=BLACK)
while True: while True:
if not switch1.value: if not switch1.value:
@ -108,8 +106,7 @@ while True:
time.sleep(0.01) time.sleep(0.01)
if not switch2.value: if not switch2.value:
print("Switch 2") print("Switch 2")
blinkaimage = Image.open("epd_bonnet_blinka_250x122.bmp") display.fill(Adafruit_EPD.WHITE)
display.image(blinkaimage)
display.display() display.display()
while not switch2.value: while not switch2.value:
time.sleep(0.01) time.sleep(0.01)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

View file

@ -1,2 +0,0 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

View file

@ -6,23 +6,18 @@ ePaper Display Shapes and Text demo using the Pillow Library.
""" """
import board
import busio
import digitalio import digitalio
import busio
import board
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from adafruit_epd.ek79686 import Adafruit_EK79686
from adafruit_epd.il0373 import Adafruit_IL0373 from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il0398 import Adafruit_IL0398 from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il91874 import Adafruit_IL91874 from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.jd79661 import Adafruit_JD79661 from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680, Adafruit_SSD1680Z from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ssd1683 import Adafruit_SSD1683
from adafruit_epd.uc8151d import Adafruit_UC8151D
from adafruit_epd.uc8179 import Adafruit_UC8179
# First define some color constants # First define some color constants
WHITE = (0xFF, 0xFF, 0xFF) WHITE = (0xFF, 0xFF, 0xFF)
@ -45,21 +40,14 @@ rst = digitalio.DigitalInOut(board.D27)
busy = digitalio.DigitalInOut(board.D17) busy = digitalio.DigitalInOut(board.D17)
# give them all to our driver # give them all to our driver
# display = Adafruit_JD79661(122, 150, # 2.13" Quad-color display
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display # display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display # display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color or mono display # display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color or mono display
# display = Adafruit_SSD1680Z(122, 250, # Newer 2.13" mono display
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display # display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display # display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display # display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display
# display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display # display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display
# display = Adafruit_UC8179(648, 480, # 5.83" mono 648x480 display # display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display
# display = Adafruit_UC8179(800, 480, # 7.5" mono 800x480 display
# display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display IL0373
# display = Adafruit_SSD1680(128, 296, # 2.9" Tri-color display SSD1680
# display = Adafruit_SSD1683(400, 300, # 4.2" 300x400 Tri-Color display
# display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display # display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display
display = Adafruit_IL0373( display = Adafruit_IL0373(
104, 104,
@ -72,9 +60,7 @@ display = Adafruit_IL0373(
busy_pin=busy, busy_pin=busy,
) )
# IF YOU HAVE A 2.13" FLEXIBLE DISPLAY OR! # IF YOU HAVE A 2.13" FLEXIBLE DISPLAY uncomment these lines!
# UC8179 5.83" or 7.5" displays
# uncomment these lines!
# display.set_black_buffer(1, False) # display.set_black_buffer(1, False)
# display.set_color_buffer(1, False) # display.set_color_buffer(1, False)

View file

@ -8,23 +8,19 @@ https://learn.adafruit.com/adafruit-eink-display-breakouts/python-code
""" """
import board
import busio
import digitalio import digitalio
import busio
import board
from PIL import Image from PIL import Image
from adafruit_epd.ek79686 import Adafruit_EK79686
from adafruit_epd.il0373 import Adafruit_IL0373 from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il0398 import Adafruit_IL0398 from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il91874 import Adafruit_IL91874 from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.jd79661 import Adafruit_JD79661 from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680, Adafruit_SSD1680Z from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ssd1683 import Adafruit_SSD1683
from adafruit_epd.uc8151d import Adafruit_UC8151D
from adafruit_epd.uc8179 import Adafruit_UC8179
# create the spi device and pins we will need # create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
@ -35,21 +31,14 @@ rst = digitalio.DigitalInOut(board.D27)
busy = digitalio.DigitalInOut(board.D17) busy = digitalio.DigitalInOut(board.D17)
# give them all to our driver # give them all to our driver
# display = Adafruit_JD79661(122, 150, # 2.13" Quad-color display
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display # display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display # display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color or mono display # display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color or mono display
# display = Adafruit_SSD1680Z(122, 250, # Newer 2.13" mono display
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display # display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display # display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display # display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display
# display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display # display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display
# display = Adafruit_UC8179(648, 480, # 5.83" mono 648x480 display # display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display
# display = Adafruit_UC8179(800, 480, # 7.5" mono 800x480 display
# display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display IL0373
# display = Adafruit_SSD1680(128, 296, # 2.9" Tri-color display SSD1680
# display = Adafruit_SSD1683(400, 300, # 4.2" 300x400 Tri-Color display
# display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display # display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display
display = Adafruit_IL0373( display = Adafruit_IL0373(
104, 104,
@ -62,9 +51,7 @@ display = Adafruit_IL0373(
busy_pin=busy, busy_pin=busy,
) )
# IF YOU HAVE A 2.13" FLEXIBLE DISPLAY OR! # IF YOU HAVE A 2.13" FLEXIBLE DISPLAY uncomment these lines!
# UC8179 5.83" or 7.5" displays
# uncomment these lines!
# display.set_black_buffer(1, False) # display.set_black_buffer(1, False)
# display.set_color_buffer(1, False) # display.set_color_buffer(1, False)
@ -95,38 +82,6 @@ image = image.crop((x, y, x + display.width, y + display.height)).convert("RGB")
# Convert to Monochrome and Add dithering # Convert to Monochrome and Add dithering
# image = image.convert("1").convert("L") # image = image.convert("1").convert("L")
if type(display) == Adafruit_JD79661:
# Create a palette with the 4 colors: Black, White, Red, Yellow
# The palette needs 768 values (256 colors × 3 channels)
palette = []
# We'll map the 256 palette indices to our 4 colors
# 0-63: Black, 64-127: Red, 128-191: Yellow, 192-255: White
for i in range(256):
if i < 64:
palette.extend([0, 0, 0]) # Black
elif i < 128:
palette.extend([255, 0, 0]) # Red
elif i < 192:
palette.extend([255, 255, 0]) # Yellow
else:
palette.extend([255, 255, 255]) # White
# Create a palette image
palette_img = Image.new("P", (1, 1))
palette_img.putpalette(palette)
# Optional: Enhance colors before dithering for better results
# from PIL import ImageEnhance
# enhancer = ImageEnhance.Color(image)
# image = enhancer.enhance(1.5) # Increase color saturation
# Quantize the image using Floyd-Steinberg dithering
image = image.quantize(palette=palette_img, dither=Image.FLOYDSTEINBERG)
# Convert back to RGB for the display driver
image = image.convert("RGB")
# Display image. # Display image.
display.image(image) display.image(image)
display.display() display.display()

View file

@ -3,12 +3,10 @@
# EInk Shield test # EInk Shield test
import time import time
import board
import busio
import digitalio import digitalio
import busio
import board
from analogio import AnalogIn from analogio import AnalogIn
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il91874 import Adafruit_IL91874 from adafruit_epd.il91874 import Adafruit_IL91874

View file

@ -1,23 +1,18 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import board
import busio
import digitalio import digitalio
import busio
from adafruit_epd.ek79686 import Adafruit_EK79686 import board
from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373 from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il0398 import Adafruit_IL0398 from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il91874 import Adafruit_IL91874 from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.jd79661 import Adafruit_JD79661 from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680, Adafruit_SSD1680Z from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ssd1683 import Adafruit_SSD1683
from adafruit_epd.uc8151d import Adafruit_UC8151D
from adafruit_epd.uc8179 import Adafruit_UC8179
# create the spi device and pins we will need # create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
@ -29,21 +24,14 @@ busy = digitalio.DigitalInOut(board.D5) # can be None to not use this pin
# give them all to our drivers # give them all to our drivers
print("Creating display") print("Creating display")
# display = Adafruit_JD79661(122, 150, # 2.13" Quad-color display
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display # display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display # display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display # display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display # display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display # display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display # display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display
# display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display # display = Adafruit_UC8151D(128, 296, # 2.9" mono flexible display
# display = Adafruit_UC8179(648, 480, # 5.83" mono 648x480 display # display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display
# display = Adafruit_UC8179(800, 480, # 7.5" mono 800x480 display
# display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display IL0373
# display = Adafruit_SSD1680(128, 296, # 2.9" Tri-color display SSD1680
# display = Adafruit_SSD1683(400, 300, # 4.2" 300x400 Tri-Color display
# display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display # display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display
display = Adafruit_IL0373( display = Adafruit_IL0373(
104, 104,
@ -56,9 +44,7 @@ display = Adafruit_IL0373(
busy_pin=busy, busy_pin=busy,
) )
# IF YOU HAVE A 2.13" FLEXIBLE DISPLAY OR! # IF YOU HAVE A 2.13" FLEXIBLE DISPLAY uncomment these lines!
# UC8179 5.83" or 7.5" displays
# uncomment these lines!
# display.set_black_buffer(1, False) # display.set_black_buffer(1, False)
# display.set_color_buffer(1, False) # display.set_color_buffer(1, False)
@ -67,33 +53,20 @@ display = Adafruit_IL0373(
# display.set_color_buffer(1, True) # display.set_color_buffer(1, True)
display.rotation = 1 display.rotation = 1
if type(display) == Adafruit_JD79661:
WHITE = Adafruit_JD79661.WHITE
BLACK = Adafruit_JD79661.BLACK
RED = Adafruit_JD79661.RED
YELLOW = Adafruit_JD79661.YELLOW
else:
WHITE = Adafruit_EPD.WHITE
BLACK = Adafruit_EPD.BLACK
RED = Adafruit_EPD.RED
# clear the buffer # clear the buffer
print("Clear buffer") print("Clear buffer")
display.fill(WHITE) display.fill(Adafruit_EPD.WHITE)
display.pixel(10, 100, BLACK) display.pixel(10, 100, Adafruit_EPD.BLACK)
print("Draw Rectangles") print("Draw Rectangles")
display.fill_rect(5, 5, 10, 10, RED) display.fill_rect(5, 5, 10, 10, Adafruit_EPD.RED)
display.rect(0, 0, 20, 30, BLACK) display.rect(0, 0, 20, 30, Adafruit_EPD.BLACK)
print("Draw lines") print("Draw lines")
if type(display) == Adafruit_JD79661: display.line(0, 0, display.width - 1, display.height - 1, Adafruit_EPD.BLACK)
display.line(0, 0, display.width - 1, display.height - 1, YELLOW) display.line(0, display.height - 1, display.width - 1, 0, Adafruit_EPD.RED)
display.line(0, display.height - 1, display.width - 1, 0, YELLOW)
else:
display.line(0, 0, display.width - 1, display.height - 1, BLACK)
display.line(0, display.height - 1, display.width - 1, 0, RED)
print("Draw text") print("Draw text")
display.text("hello world", 25, 10, BLACK) display.text("hello world", 25, 10, Adafruit_EPD.BLACK)
display.display() display.display()

View file

@ -1,42 +0,0 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import time
import board
import busio
import digitalio
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.ssd1680 import Adafruit_SSD1680
# create the spi device and pins we will need
spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None)
epd_cs = digitalio.DigitalInOut(board.EPD_CS)
epd_dc = digitalio.DigitalInOut(board.EPD_DC)
epd_reset = digitalio.DigitalInOut(board.EPD_RESET)
epd_busy = digitalio.DigitalInOut(board.EPD_BUSY)
srcs = None
display = Adafruit_SSD1680(
122,
250,
spi,
cs_pin=epd_cs,
dc_pin=epd_dc,
sramcs_pin=srcs,
rst_pin=epd_reset,
busy_pin=epd_busy,
)
display.rotation = 3
display.fill(Adafruit_EPD.WHITE)
display.fill_rect(20, 20, 50, 60, Adafruit_EPD.BLACK)
display.hline(80, 30, 60, Adafruit_EPD.BLACK)
display.vline(80, 30, 60, Adafruit_EPD.BLACK)
# draw repeatedly with pauses
while True:
display.display()
time.sleep(15)

View file

@ -1,98 +0,0 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import time
import board
import busio
import digitalio
from PIL import Image, ImageDraw, ImageFont
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.ssd1680 import Adafruit_SSD1680
# create the spi device and pins we will need
spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None)
epd_cs = digitalio.DigitalInOut(board.EPD_CS)
epd_dc = digitalio.DigitalInOut(board.EPD_DC)
epd_reset = digitalio.DigitalInOut(board.EPD_RESET)
epd_busy = digitalio.DigitalInOut(board.EPD_BUSY)
srcs = None
display = Adafruit_SSD1680(
122,
250,
spi,
cs_pin=epd_cs,
dc_pin=epd_dc,
sramcs_pin=srcs,
rst_pin=epd_reset,
busy_pin=epd_busy,
)
display.rotation = 3
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = display.width
height = display.height
image = Image.new("RGB", (width, height))
WHITE = (0xFF, 0xFF, 0xFF)
BLACK = (0x00, 0x00, 0x00)
# clear the display
display.fill(Adafruit_EPD.WHITE)
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# empty it
draw.rectangle((0, 0, width, height), fill=WHITE)
# Draw an outline box
draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = 5
shape_width = 30
top = padding
bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes.
x = padding
# Draw an ellipse.
draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE)
x += shape_width + padding
# Draw a rectangle.
draw.rectangle((x, top, x + shape_width, bottom), outline=WHITE, fill=BLACK)
x += shape_width + padding
# Draw a triangle.
draw.polygon(
[(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)],
outline=BLACK,
fill=WHITE,
)
x += shape_width + padding
# Draw an X.
draw.line((x, bottom, x + shape_width, top), fill=BLACK)
draw.line((x, top, x + shape_width, bottom), fill=BLACK)
x += shape_width + padding
# Load default font.
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
# Alternatively load a TTF font. Make sure the .ttf font
# file is in the same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8)
# Write two lines of text.
draw.text((x, top), "Hello", font=font, fill=BLACK)
draw.text((x, top + 20), "World!", font=font, fill=BLACK)
display.image(image)
display.display()
time.sleep(10)
blinkaimage = Image.open("examples/epd_bonnet_blinka_250x122.bmp")
display.image(blinkaimage)
display.display()

View file

@ -1,3 +0,0 @@
# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense

View file

@ -1,47 +0,0 @@
# SPDX-FileCopyrightText: 2022 Alec Delaney for Adafruit Industries
#
# SPDX-License-Identifier: MIT
[build-system]
requires = [
"setuptools",
"wheel",
"setuptools-scm",
]
[project]
name = "adafruit-circuitpython-epd"
description = "CircuitPython library for EPD e-ink displays."
version = "0.0.0+auto.0"
readme = "README.rst"
authors = [
{name = "Adafruit Industries", email = "circuitpython@adafruit.com"}
]
urls = {Homepage = "https://github.com/adafruit/Adafruit_CircuitPython_EPD"}
keywords = [
"adafruit",
"eink",
"e-ink",
"display",
"epd",
"hardware",
"micropython",
"circuitpython",
]
license = {text = "MIT"}
classifiers = [
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Embedded Systems",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
]
dynamic = ["dependencies", "optional-dependencies"]
[tool.setuptools]
packages = ["adafruit_epd"]
[tool.setuptools.dynamic]
dependencies = {file = ["requirements.txt"]}
optional-dependencies = {optional = {file = ["optional_requirements.txt"]}}

View file

@ -1,8 +1,7 @@
# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# #
# SPDX-License-Identifier: Unlicense # SPDX-License-Identifier: Unlicense
Adafruit-Blinka Adafruit-Blinka
adafruit-circuitpython-busdevice adafruit-circuitpython-busdevice
adafruit-circuitpython-framebuf adafruit-circuitpython-framebuf
typing-extensions~=4.0

105
ruff.toml
View file

@ -1,105 +0,0 @@
# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
target-version = "py38"
line-length = 100
[lint]
preview = true
select = ["I", "PL", "UP"]
extend-select = [
"D419", # empty-docstring
"E501", # line-too-long
"W291", # trailing-whitespace
"PLC0414", # useless-import-alias
"PLC2401", # non-ascii-name
"PLC2801", # unnecessary-dunder-call
"PLC3002", # unnecessary-direct-lambda-call
"E999", # syntax-error
"PLE0101", # return-in-init
"F706", # return-outside-function
"F704", # yield-outside-function
"PLE0116", # continue-in-finally
"PLE0117", # nonlocal-without-binding
"PLE0241", # duplicate-bases
"PLE0302", # unexpected-special-method-signature
"PLE0604", # invalid-all-object
"PLE0605", # invalid-all-format
"PLE0643", # potential-index-error
"PLE0704", # misplaced-bare-raise
"PLE1141", # dict-iter-missing-items
"PLE1142", # await-outside-async
"PLE1205", # logging-too-many-args
"PLE1206", # logging-too-few-args
"PLE1307", # bad-string-format-type
"PLE1310", # bad-str-strip-call
"PLE1507", # invalid-envvar-value
"PLE2502", # bidirectional-unicode
"PLE2510", # invalid-character-backspace
"PLE2512", # invalid-character-sub
"PLE2513", # invalid-character-esc
"PLE2514", # invalid-character-nul
"PLE2515", # invalid-character-zero-width-space
"PLR0124", # comparison-with-itself
"PLR0202", # no-classmethod-decorator
"PLR0203", # no-staticmethod-decorator
"UP004", # useless-object-inheritance
"PLR0206", # property-with-parameters
"PLR0904", # too-many-public-methods
"PLR0911", # too-many-return-statements
"PLR0912", # too-many-branches
"PLR0913", # too-many-arguments
"PLR0914", # too-many-locals
"PLR0915", # too-many-statements
"PLR0916", # too-many-boolean-expressions
"PLR1702", # too-many-nested-blocks
"PLR1704", # redefined-argument-from-local
"PLR1711", # useless-return
"C416", # unnecessary-comprehension
"PLR1733", # unnecessary-dict-index-lookup
"PLR1736", # unnecessary-list-index-lookup
# ruff reports this rule is unstable
#"PLR6301", # no-self-use
"PLW0108", # unnecessary-lambda
"PLW0120", # useless-else-on-loop
"PLW0127", # self-assigning-variable
"PLW0129", # assert-on-string-literal
"B033", # duplicate-value
"PLW0131", # named-expr-without-context
"PLW0245", # super-without-brackets
"PLW0406", # import-self
"PLW0602", # global-variable-not-assigned
"PLW0603", # global-statement
"PLW0604", # global-at-module-level
# fails on the try: import typing used by libraries
#"F401", # unused-import
"F841", # unused-variable
"E722", # bare-except
"PLW0711", # binary-op-exception
"PLW1501", # bad-open-mode
"PLW1508", # invalid-envvar-default
"PLW1509", # subprocess-popen-preexec-fn
"PLW2101", # useless-with-lock
"PLW3301", # nested-min-max
]
ignore = [
"PLR2004", # magic-value-comparison
"UP030", # format literals
"PLW1514", # unspecified-encoding
"PLR0913", # too-many-arguments
"PLR0915", # too-many-statements
"PLR0917", # too-many-positional-arguments
"PLR0904", # too-many-public-methods
"PLR0912", # too-many-branches
"PLR0916", # too-many-boolean-expressions
]
[format]
line-ending = "lf"

60
setup.py Normal file
View file

@ -0,0 +1,60 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""A setuptools based setup module.
See:
https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject
"""
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
long_description = f.read()
setup(
name="adafruit-circuitpython-epd",
use_scm_version=True,
setup_requires=["setuptools_scm"],
description="CircuitPython library for EPD e-ink displays.",
long_description=long_description,
long_description_content_type="text/x-rst",
# The project's main homepage.
url="https://github.com/adafruit/Adafruit_CircuitPython_EPD",
# Author details
author="Adafruit Industries",
author_email="circuitpython@adafruit.com",
install_requires=[
"Adafruit-Blinka",
"adafruit-circuitpython-busdevice",
"adafruit-circuitpython-framebuf",
],
# Choose your license
license="MIT",
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
# What does your project relate to?
keywords="adafruit eink e-ink display epd hardware micropython circuitpython",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
packages=["adafruit_epd"],
)