From b5287f69fbd9e506330b67085f640749d3867084 Mon Sep 17 00:00:00 2001 From: Aaron Ciuffo Date: Sat, 18 Nov 2023 15:55:33 +0100 Subject: [PATCH] Py 11 (#142) * deprecate crypto plugin * reduce to minimal required set focus debian package search to just app folder reduce to minimal set of required packages, remove IT8951 update Pipfile remove devel cleaning add python 3.11 detection fix line break remove uneeded line add better logging move IT8951 to development reorder functions debian packages required for jupyter devel ignore IT8951 improved development env. script add development instructions install proper IT8951 version use abort add new install script revert to main remove badly named file update rename to follow pattern update required debian packages simplified devel setup script add development requirements remove pinning ignore venv_activate update entry script update installer script switch to init_devel file update docs remove Pipfiles fix logic error update waveshare libs move update script change path update --- .gitignore | 5 +- Pipfile | 38 -- Pipfile.lock | 507 ---------------- documentation/Developing_PaperPi.md | 53 ++ install/install.sh | 554 ++++++------------ install/paperpi | 11 +- install/signal.txt | 0 install_waveshare_libs.sh | 44 -- paperpi/debian_packages-paperpi.txt | 3 +- paperpi/waveshare_epd/epd13in3k.py | 187 ++++++ paperpi/waveshare_epd/epd2in13_V4.py | 350 +++++++++++ paperpi/waveshare_epd/epd2in9_V2.py | 167 ++++++ paperpi/waveshare_epd/epd4in2_V2.py | 530 +++++++++++++++++ paperpi/waveshare_epd/epdconfig.py | 2 +- paperpi/waveshare_epd/epdconfig.py_bak | 243 ++++++++ .../crypto/README.md | 0 .../crypto/README_additional.md | 0 .../crypto/__init__.py | 0 .../crypto/constants.py | 0 .../crypto/crypto.ipynb | 0 .../crypto/crypto.layout-L-sample.png | Bin .../crypto/crypto.py | 0 .../crypto/crypto.ticker_hd-L-sample.png | Bin .../crypto/crypto.ticker_simple-L-sample.png | Bin .../crypto/debian_packages-crypto.txt | 0 .../crypto/images/unknown.png | Bin .../crypto/layout.py | 0 .../crypto/requirements-crypto.txt | 0 .../crypto/requirements-crypto_hidden.txt | 0 .../crypto/sample.py | 0 requirements.txt | 8 + utilities/create_devel_environment.sh | 275 --------- utilities/debian_packages-jupyter_devel.txt | 1 + utilities/init_devel_environment.sh | 310 ++++++++++ utilities/install_waveshare_libs.sh | 57 ++ utilities/requirements-devel.txt | 1 + utilities/requirements-jupyter_devel.txt | 1 + 37 files changed, 2114 insertions(+), 1233 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 documentation/Developing_PaperPi.md delete mode 100644 install/signal.txt delete mode 100755 install_waveshare_libs.sh create mode 100644 paperpi/waveshare_epd/epd13in3k.py create mode 100644 paperpi/waveshare_epd/epd2in13_V4.py create mode 100644 paperpi/waveshare_epd/epd4in2_V2.py create mode 100644 paperpi/waveshare_epd/epdconfig.py_bak rename {paperpi/plugins => plugins_depricated}/crypto/README.md (100%) rename {paperpi/plugins => plugins_depricated}/crypto/README_additional.md (100%) rename {paperpi/plugins => plugins_depricated}/crypto/__init__.py (100%) rename {paperpi/plugins => plugins_depricated}/crypto/constants.py (100%) rename {paperpi/plugins => plugins_depricated}/crypto/crypto.ipynb (100%) rename {paperpi/plugins => plugins_depricated}/crypto/crypto.layout-L-sample.png (100%) rename {paperpi/plugins => plugins_depricated}/crypto/crypto.py (100%) rename {paperpi/plugins => plugins_depricated}/crypto/crypto.ticker_hd-L-sample.png (100%) rename {paperpi/plugins => plugins_depricated}/crypto/crypto.ticker_simple-L-sample.png (100%) rename {paperpi/plugins => plugins_depricated}/crypto/debian_packages-crypto.txt (100%) rename {paperpi/plugins => plugins_depricated}/crypto/images/unknown.png (100%) rename {paperpi/plugins => plugins_depricated}/crypto/layout.py (100%) rename {paperpi/plugins => plugins_depricated}/crypto/requirements-crypto.txt (100%) rename {paperpi/plugins => plugins_depricated}/crypto/requirements-crypto_hidden.txt (100%) rename {paperpi/plugins => plugins_depricated}/crypto/sample.py (100%) create mode 100644 requirements.txt delete mode 100755 utilities/create_devel_environment.sh create mode 100644 utilities/debian_packages-jupyter_devel.txt create mode 100755 utilities/init_devel_environment.sh create mode 100755 utilities/install_waveshare_libs.sh create mode 100644 utilities/requirements-devel.txt create mode 100644 utilities/requirements-jupyter_devel.txt diff --git a/.gitignore b/.gitignore index f2b9e1a..b30f176 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.pyo .python-version -Pipfile.lock */build/* */dist/* build/* @@ -12,3 +11,7 @@ tmp/* .vscode* version.txt paperpi/plugins/*/library +paperpi/IT8951 +venv_* +*__pycache__* +venv_activate \ No newline at end of file diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 1a76bd1..0000000 --- a/Pipfile +++ /dev/null @@ -1,38 +0,0 @@ -[[source]] -url = "https://www.piwheels.org/simple/" -verify_ssl = true -name = "piwheels" - -[[source]] -url = "https://www.pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -it8951 = {editable = true, git = "https://github.com/GregDMeyer/IT8951.git"} -epdlib = "*" -argconfigparse = "*" - -[requires] -python_version = "3" - -[dev-packages] -dictor = "*" -requests = "*" -pytz = "*" -feedparser = "*" -python-dateutil = "*" -currency-symbols = "*" -pycoingecko = "*" -pygal = "*" -qrcode = "*" -cairocffi = "*" -cffi ="*" -psutil = "*" -pillow = "*" -epdlib = "*" -querylms = "*" -cairosvg = "*" -ipykernel = "*" -pipreqs = "*" - diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 584ebef..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,507 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "61c6a9ed7766c930284e113183a0cdf9879d311c0a6fc645852d7bc65e5d562c" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3" - }, - "sources": [ - { - "name": "piwheels", - "url": "https://www.piwheels.org/simple/", - "verify_ssl": true - }, - { - "name": "pypi", - "url": "https://www.pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "argconfigparse": { - "hashes": [ - "sha256:fb8dccb93f08b1f86461ed472115d94068b900cc7560d6efb6ddd3415f3d84be" - ], - "index": "piwheels", - "version": "==0.2.7" - }, - "epdlib": { - "hashes": [ - "sha256:053da4543cad6a18b58080c64c3616c79bb6d2f264cb6f32eb2d35bd80aa1190" - ], - "index": "piwheels", - "version": "==0.6.1.3" - }, - "it8951": { - "editable": true, - "git": "https://github.com/GregDMeyer/IT8951.git", - "ref": "67215164a7fc471bc6904f72ad55e51030905a97" - }, - "pillow": { - "hashes": [ - "sha256:c3d151125cf7fad504c9d2b568f546846cb9481169e09c1092f58715d1209e48" - ], - "markers": "python_version >= '3.8'", - "version": "==10.0.0" - }, - "rpi.gpio": { - "hashes": [ - "sha256:231f6142c25975a7e39b96faf4905f05f97dba6809e8c5f0d58f284b35b4b821", - "sha256:5073d1972727cfad38a1a42f02da91dc41f137679290aa804ab6c410168347ac", - "sha256:e5dfec2c4ccb7dbe9eef3dfc76a3b04121fc62d77fd8fbe1a8e841468a1b0c4c" - ], - "version": "==0.7.1" - }, - "spidev": { - "hashes": [ - "sha256:202698d9f7906cca548c301b97eee117bc029642af3e743b28597f752d11c0ee", - "sha256:ef47ae501d5b307ce7411e3ddab4b4d04fa31fdaed5e5730a4e3336f65c5f76b" - ], - "version": "==3.6" - } - }, - "develop": { - "asttokens": { - "hashes": [ - "sha256:b15adaccddeeae633d761d331f0f3804d1921f4524067618b2b7ffbb8c55042e" - ], - "version": "==2.2.1" - }, - "backcall": { - "hashes": [ - "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" - ], - "version": "==0.2.0" - }, - "cairocffi": { - "hashes": [ - "sha256:7541137a2eb36e875247b9150eda16a34dc8a0df71471ca65d900c4775635ea5" - ], - "index": "piwheels", - "version": "==1.6.1" - }, - "cairosvg": { - "hashes": [ - "sha256:a2f6439657d9720ec39052f29dc3ca758f34c327a42fd5255fddd67dfe671a15" - ], - "index": "piwheels", - "version": "==2.7.1" - }, - "certifi": { - "hashes": [ - "sha256:4e4d84b05d4572339352afe85f0490367f5b8572b7f8d3f2373dffd642210f2d" - ], - "markers": "python_version >= '3.6'", - "version": "==2023.7.22" - }, - "cffi": { - "hashes": [ - "sha256:6121721a6976cbf2fc4d2807fded73d92917c911bbc8ba2c7310321d7b760230", - "sha256:a1e3a74910df7f5e703e5b0009d411171b808e45f4826fac0568fdab1a154185", - "sha256:bf9242179d15bac1bf6d9b03d83d058019b3f6bca8c08ad699de315e5fbfa6d3" - ], - "index": "piwheels", - "version": "==1.15.1" - }, - "charset-normalizer": { - "hashes": [ - "sha256:961de80416b72ef32233a659535db45951dd86adf037ace0796a74fd8ad4ffde" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.2.0" - }, - "comm": { - "hashes": [ - "sha256:e29eb362f63e48a8db37c29b669cc11de82d3e1be77a9251becdb8da1d9cb9f8" - ], - "markers": "python_version >= '3.6'", - "version": "==0.1.4" - }, - "cssselect2": { - "hashes": [ - "sha256:63fee6b00baea10c21b39553577dc8fd87639984c5b17fed86e93e7ff9ed9f2c" - ], - "markers": "python_version >= '3.7'", - "version": "==0.7.0" - }, - "currency-symbols": { - "hashes": [ - "sha256:5faffebcaee6e63f16be4f7a879f1aa9ca5f9f39afa2aad1856c43e4e8f8031f" - ], - "index": "piwheels", - "version": "==2.0.3" - }, - "debugpy": { - "hashes": [ - "sha256:33edebdca433f2ab2fefc6049401c2f4e6fd3aa884c39e0d92d42d3b9760917b", - "sha256:c40a2b3f55bb9eb2cc606efdf32bd69a850be6f6e4dba7a211fc9edac8d786eb" - ], - "markers": "python_version >= '3.7'", - "version": "==1.6.7.post1" - }, - "decorator": { - "hashes": [ - "sha256:6f519e77644a392d3054e528ba8db527df4246be581d4d43b14f0aacace79cbd" - ], - "markers": "python_version >= '3.5'", - "version": "==5.1.1" - }, - "defusedxml": { - "hashes": [ - "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.7.1" - }, - "dictor": { - "hashes": [ - "sha256:73792a09cd7cffcf355e172999cd5b2b817f033f6c0a83f590736a96c8c11f78" - ], - "index": "piwheels", - "version": "==0.1.11" - }, - "docopt": { - "hashes": [ - "sha256:15fde8252aa9f2804171014d50d069ffbf42c7a50b7d74bcbb82bfd5700fcfc2" - ], - "version": "==0.6.2" - }, - "epdlib": { - "hashes": [ - "sha256:053da4543cad6a18b58080c64c3616c79bb6d2f264cb6f32eb2d35bd80aa1190" - ], - "index": "piwheels", - "version": "==0.6.1.3" - }, - "executing": { - "hashes": [ - "sha256:8a965b7445f3a47d99a8eee45005119eda7efda96242c56d92c2257102379dda" - ], - "version": "==1.2.0" - }, - "feedparser": { - "hashes": [ - "sha256:0b5a6848e337dcec930cdf84a6add0e6201951df5c2f840d22b963d1269b5a65" - ], - "index": "piwheels", - "version": "==6.0.10" - }, - "idna": { - "hashes": [ - "sha256:bcac1132a4eadea8321490704e2349b752e29c6ec2f1c27d372010e76ebd3fa1" - ], - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "importlib-metadata": { - "hashes": [ - "sha256:eee927b02daa5ef8a9da352c7edb8d87e3b0fb0ac03c36ec3b0c16a735819c74" - ], - "markers": "python_version < '3.10'", - "version": "==6.8.0" - }, - "ipykernel": { - "hashes": [ - "sha256:c8a2430b357073b37c76c21c52184db42f6b4b0e438e1eb7df3c4440d120497c" - ], - "index": "piwheels", - "version": "==6.25.1" - }, - "ipython": { - "hashes": [ - "sha256:364c04fab135fb30572f194f3fecfc6bfcca848eed39e5c269e10d98f66d00db" - ], - "markers": "python_version >= '3.9'", - "version": "==8.14.0" - }, - "jedi": { - "hashes": [ - "sha256:d97970bddbc6c98a0dab01ab33b53e3a8636feb6bf15bc83f831bdec3def4d26" - ], - "markers": "python_version >= '3.6'", - "version": "==0.19.0" - }, - "jupyter-client": { - "hashes": [ - "sha256:7441af0c0672edc5d28035e92ba5e32fadcfa8a4e608a434c228836a89df6158" - ], - "markers": "python_version >= '3.8'", - "version": "==8.3.0" - }, - "jupyter-core": { - "hashes": [ - "sha256:ae9036db959a71ec1cac33081eeb040a79e681f08ab68b0883e9a676c7a90dce" - ], - "markers": "python_version >= '3.8'", - "version": "==5.3.1" - }, - "matplotlib-inline": { - "hashes": [ - "sha256:3d7018118d28c556e3746445cbaa61bc04018efc6b1994dd5618fe13fbed736d" - ], - "markers": "python_version >= '3.5'", - "version": "==0.1.6" - }, - "nest-asyncio": { - "hashes": [ - "sha256:e02a5e2521add8870548153c12bf3017c7fa38f876b0d3fdc6c15ebe713ff3fd" - ], - "markers": "python_version >= '3.5'", - "version": "==1.5.7" - }, - "packaging": { - "hashes": [ - "sha256:135a6a678ccdfa43bfe57118b60922c721550f6c27bec2e1b08f60ba3924fe3e" - ], - "markers": "python_version >= '3.7'", - "version": "==23.1" - }, - "parso": { - "hashes": [ - "sha256:9c0ab364bdef44019b358a7263f2cad8f68a7df1ac075b54bcde2eee36e38a50" - ], - "markers": "python_version >= '3.6'", - "version": "==0.8.3" - }, - "pexpect": { - "hashes": [ - "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937" - ], - "markers": "sys_platform != 'win32'", - "version": "==4.8.0" - }, - "pickleshare": { - "hashes": [ - "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" - ], - "version": "==0.7.5" - }, - "pillow": { - "hashes": [ - "sha256:c3d151125cf7fad504c9d2b568f546846cb9481169e09c1092f58715d1209e48" - ], - "markers": "python_version >= '3.8'", - "version": "==10.0.0" - }, - "pipreqs": { - "hashes": [ - "sha256:dadafd0c71cf9a60e169881b33a0298186bc0f0d81675a93e81bc7fe371ab9ed" - ], - "index": "piwheels", - "version": "==0.4.13" - }, - "platformdirs": { - "hashes": [ - "sha256:764db339fa30fdca66d5c819ac9468f5efd2e2e12053163bd60fea9409d2e3af" - ], - "markers": "python_version >= '3.7'", - "version": "==3.10.0" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:a3ff6f69f7e5a7951c972956d65565fd3e49b43a9246aff63102a40dd31ce874" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.39" - }, - "psutil": { - "hashes": [ - "sha256:56f7bc39867415d4be0d2e8537ec59643b2c253d1d38214db9874d48570d0925", - "sha256:7337415f7f8d238c310f2e5fb7ad5de6a4f709d4854bb83baad44cd16600326c" - ], - "index": "piwheels", - "version": "==5.9.5" - }, - "ptyprocess": { - "hashes": [ - "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35" - ], - "version": "==0.7.0" - }, - "pure-eval": { - "hashes": [ - "sha256:a169c3f7e38290e2b9dd7da74f5578909e1358aaf6b97d9adee59c56e4eb4d5d" - ], - "version": "==0.2.2" - }, - "pycoingecko": { - "hashes": [ - "sha256:0f57a079ca8aa9f9a03d937431044410d97a4d2c0d0260919b6d1467af5d9693" - ], - "index": "piwheels", - "version": "==3.1.0" - }, - "pycparser": { - "hashes": [ - "sha256:ab326306c89cc646bc81ba2337c513f967faf2b3457985e1c63180adf1ada044" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.21" - }, - "pygal": { - "hashes": [ - "sha256:45bcdffbfda91085d03c6be7f27554a657ba317a3a839b3039e7e318e9dc4f54", - "sha256:82c1a2d1248d646ff93f0c106e8fefc16c1a9f2e900ced3481f12e554409e4d8" - ], - "index": "piwheels", - "version": "==3.0.0" - }, - "pygments": { - "hashes": [ - "sha256:ca6616a95d7517ca5c636e9b865bcb47035881de11845ee5c8ba9f6cfbd39783" - ], - "markers": "python_version >= '3.7'", - "version": "==2.16.1" - }, - "pypng": { - "hashes": [ - "sha256:901b9780745cb6815288df5b93ad04182eb9438d503ae764b99c31a21dc0c3b0" - ], - "version": "==0.20220715.0" - }, - "python-dateutil": { - "hashes": [ - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "index": "piwheels", - "version": "==2.8.2" - }, - "pytz": { - "hashes": [ - "sha256:dcb23b3d3f96b1c61a06ccc55e8b19dbb430b7571dc8a112432909a14dd64063" - ], - "index": "piwheels", - "version": "==2023.3" - }, - "pyzmq": { - "hashes": [ - "sha256:0fee2cca7d73f0df033bf04963c1aac2e692d0f177f8ac2c20f07caba52b7456", - "sha256:17f66b00443c37f47913dfb8ba55cb89a8bd12d28e3710d88677d875d2739d74", - "sha256:5a140e626c02451e429bf83e4d391618cb0b42d5cb235d832c8eb9629f986e37", - "sha256:85f8ce5396bc90d690b9475143a6de1add20d5662c35bc605f81fb65f839251f", - "sha256:9ca49c7c144a35374b6501969505418b9a6d9e8588cfb4955b5edd389ca9bd14", - "sha256:a42a570fda7a386155c357518e1dbde03c6eb9d38a3df2f40445c71fb29d8c04" - ], - "markers": "python_version >= '3.6'", - "version": "==25.1.1" - }, - "qrcode": { - "hashes": [ - "sha256:7bc1fff114bc8b76d5fd56e920f9037f2bface7bb548afa61cd89c86136b912a" - ], - "index": "piwheels", - "version": "==7.4.2" - }, - "querylms": { - "hashes": [ - "sha256:71819ea3fc1448021200a1c716829a4c7ce0c5be609f5f0c0f82a9346635e696" - ], - "index": "piwheels", - "version": "==0.2.2.1" - }, - "requests": { - "hashes": [ - "sha256:471e7795897eff62a8e31f26f241e3e67ee80d1bd0f64236538a3dda8d3f1acc" - ], - "index": "piwheels", - "version": "==2.31.0" - }, - "rpi.gpio": { - "hashes": [ - "sha256:231f6142c25975a7e39b96faf4905f05f97dba6809e8c5f0d58f284b35b4b821", - "sha256:5073d1972727cfad38a1a42f02da91dc41f137679290aa804ab6c410168347ac", - "sha256:e5dfec2c4ccb7dbe9eef3dfc76a3b04121fc62d77fd8fbe1a8e841468a1b0c4c" - ], - "version": "==0.7.1" - }, - "sgmllib3k": { - "hashes": [ - "sha256:91c6e449f1df4f71f74327e8a364073b1ddd2e5414d79c6de43706aabafac743" - ], - "version": "==1.0.0" - }, - "six": { - "hashes": [ - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "spidev": { - "hashes": [ - "sha256:202698d9f7906cca548c301b97eee117bc029642af3e743b28597f752d11c0ee", - "sha256:ef47ae501d5b307ce7411e3ddab4b4d04fa31fdaed5e5730a4e3336f65c5f76b" - ], - "version": "==3.6" - }, - "stack-data": { - "hashes": [ - "sha256:e33c24dd63587fa68bb9bd7d0c380e4c1960d75cfe4e0ee4aaad132cea832500" - ], - "version": "==0.6.2" - }, - "tinycss2": { - "hashes": [ - "sha256:137efd731e2f4b24b0f91c0360e6a2510e8d4c78a7eed828684ce83bdc581166" - ], - "markers": "python_version >= '3.7'", - "version": "==1.2.1" - }, - "tornado": { - "hashes": [ - "sha256:defabed9ff638f8aab15deda45cf75d9f96cd331e67bc29ed25bfc0de3fcce7e" - ], - "markers": "python_version >= '3.8'", - "version": "==6.3.3" - }, - "traitlets": { - "hashes": [ - "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8" - ], - "markers": "python_version >= '3.7'", - "version": "==5.9.0" - }, - "typing-extensions": { - "hashes": [ - "sha256:cabd4dcc82c306fe7dc7f141b7b8b83999c16f80701079e8a2431d05070580b9" - ], - "markers": "python_version >= '3.7'", - "version": "==4.7.1" - }, - "urllib3": { - "hashes": [ - "sha256:b256d3c847397b76eca8a1d69f326d7d77a77803a19745b535cd205cd2eca229" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.4" - }, - "wcwidth": { - "hashes": [ - "sha256:dc37029ea17a1ce504bc65cb644df6f1b08da98ee918ffab1e04fc6b9f3c6222" - ], - "version": "==0.2.6" - }, - "webencodings": { - "hashes": [ - "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78" - ], - "version": "==0.5.1" - }, - "yarg": { - "hashes": [ - "sha256:4f9cebdc00fac946c9bf2783d634e538a71c7d280a4d806d45fd4dc0ef441492" - ], - "version": "==0.1.9" - }, - "zipp": { - "hashes": [ - "sha256:ffebb2bccce49efecaa7b6d4d273d64e047c4d0ea72b6f04c05a11a9f49a753d" - ], - "markers": "python_version >= '3.8'", - "version": "==3.16.2" - } - } -} diff --git a/documentation/Developing_PaperPi.md b/documentation/Developing_PaperPi.md new file mode 100644 index 0000000..0d4fc0b --- /dev/null +++ b/documentation/Developing_PaperPi.md @@ -0,0 +1,53 @@ +# Developing for PaperPi + +## Quick Start + +1. Clone the repo: `git clone https://github.com/txoof/PaperPi.git` +2. From the repo root run the development init script: `./utilities/init_devel_environment.sh -h` +3. Start developing - see the notes below about [required packages](#required-debian-packages) + + +## Development Environment + +The development init script will create a python virtual environment, prompt for required Debian package. To activate the virtual environment use `source .PaperPi/utilities/venv_activate` or alternatively `source PaperPi/paperpi_venv/bin/activate`. + +PaperPi can be developed in Jupyter notebooks. Runing the init script with the `-j` option will create the venv, install the appropriate Jupyter related packages and install the Jupyter kernel. To start a Jupyter session and connect from a remote computer on the same network use the command below, then connect to the supplied URL. + +Command: +``` +MYHOST=$(hostname -I | cut -d " " -f 1); jupyter notebook --ip=$MYHOST --no-browser +``` + +Output: +```bash +pi@bookworm32t:~/PaperPi $ MYHOST=$(hostname -I | cut -d " " -f 1); jupyter notebook --ip=$MYHOST --no-browser +[I 18:53:43.302 NotebookApp] Serving notebooks from local directory: /home/pi/PaperPi +[I 18:53:43.302 NotebookApp] Jupyter Notebook 6.4.12 is running at: +[I 18:53:43.302 NotebookApp] http://192.168.1.209:8888/?token=ed2bda1679e3f2c8c8b852df3d1f44fc5937f7674404fd2a +[I 18:53:43.303 NotebookApp] or http://127.0.0.1:8888/?token=ed2bda1679e3f2c8c8b852df3d1f44fc5937f7674404fd2a +[I 18:53:43.303 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). +[C 18:53:43.323 NotebookApp] + + To access the notebook, open this file in a browser: + file:///home/pi/.local/share/jupyter/runtime/nbserver-22902-open.html + Or copy and paste one of these URLs: + http://192.168.1.209:8888/?token=ed2bda1679e3f2c8c8b852df3d1f44fc5937f7674404fd2a + or http://127.0.0.1:8888/?token=ed2bda1679e3f2c8c8b852df3d1f44fc5937f7674404fd2a +``` + +## Required Debian Packages + +Basic development depends on the packages listeded here + +- [debian_packages-paperpi](../paperpi/debian_packages-paperpi.txt) + +Some plugins may have additional Debian requirements. These plugins are documented in `./paperpi/plugins/[plugin_name]/debian_packages-plugin_name..txt` + +If your plugin requires additional Debian packages to function, make sure to list them as a bash style array. See the example below: + +```bash +# list the packages using the full and complete package name +# NOTE that bash arrays are always in parentheses, do not use commas and there is +# no space between the variable name and the `=` sign. +DEBPKG=( "libtiff-dev" "libopenjp2-7" "python3-pip" "python3-venv" ) +``` \ No newline at end of file diff --git a/install/install.sh b/install/install.sh index ceeb181..a499783 100755 --- a/install/install.sh +++ b/install/install.sh @@ -13,7 +13,7 @@ SCRIPT_DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd ) APPNAME="paperpi" LOCALPATH="$SCRIPT_DIR/../paperpi" -INSTALLPATH="/usr/local/" +INSTALLPATH="/usr/local/$APPNAME" BINPATH="/usr/local/bin/" CWD=$(pwd) @@ -28,7 +28,35 @@ SYSTEMD_UNIT_PATH="/etc/systemd/system/$SYSTEMD_UNIT_FILE_NAME" CONFIG_FILE_NAME=$APPNAME.ini SYSTEM_CONFIG_PATH=/etc/default/$CONFIG_FILE_NAME -SKIP_OS_CHECK=0 +PY_VERSION=$(python3 -c 'import sys; print("{}.{}".format(sys.version_info.major, sys.version_info.minor))') +PY_MAJOR=$(echo "$PY_VERSION" | cut -d. -f1) +PY_MINOR=$(echo "$PY_VERSION" | cut -d. -f2) + +if [ $PY_MINOR -gt 10 ] +then + PY_311_OPTS="--user --break-system-packages" +else + PY_311_OPTS="--user" +fi + + +function Help { + echo " + Install/Uninstall $APPNAME to run at boot + + This installer will install $APPNAME as a daemon service to + run at system startup. + + This installer must be run as root. + + options: + -h This help screen + -u uninstall $APPNAME + -p uninstall $APPNAME and purge all config files + -s skip OS version check for manuall install on 64 bit systems + " + +} function abort { # abort installation with message @@ -38,22 +66,6 @@ function abort { exit 1 } -function check_os { - if [ "$SKIP_OS_CHECK" -eq 1 ] - then - echo "skiping OS version checking. YOU'RE ON YOUR OWN!" - return 0 - fi - - echo "checking OS" - long_bit=$(getconf LONG_BIT) - if [ ! "$long_bit" -eq 32 ] - then - abort "PaperPi is supported only on 32 bit versions of RaspberryPi OS. Your version: $long_bit bit. Check README for manual install instructions" - fi -} - - function stop_daemon { echo "checking if $SYSTEMD_UNIT_FILE_NAME is running" @@ -71,277 +83,231 @@ function stop_daemon { abort fi else - echo " $SYSTEMD_UNIT_FILE_NAME not running" + echo "$SYSTEMD_UNIT_FILE_NAME not running" fi echo "done" } -# install requirements from the plugin requirements-*.txt files -function install_plugin_requirements { - - if [ $INSTALL -gt 0 ] - then - echo "Installing requirements in virtual environment for $APPNAME plugins" - pushd $INSTALLPATH/$APPNAME - # find all the plugin requirements and install using pipenv install - tempfile=$(mktemp) - find $SCRIPT_DIR/../paperpi/plugins -type f -name "requirements-*.txt" -exec cat {} >> $tempfile \; - echo "installing Plugin requirements:" - cat $tempfile - if ! command pipenv install -r $tempfile +function check_os { + if [ "$SKIP_OS_CHECK" -eq 1 ] then - popd - abort "failed to install python modules" + echo "skiping OS version checking. YOU'RE ON YOUR OWN!" + return 0 fi - popd - else - echo "" - fi + echo "Checking OS" + + long_bit=$(getconf LONG_BIT) + if [ ! "$long_bit" -eq 32 ] + then + abort "PaperPi is supported only on 32 bit versions of RaspberryPi OS. Your version: $long_bit bit. Check README for manual install instructions" + fi + echo "OS OK" } -function copy_files { +function check_permissions { + echo "Checking permisisons" + if [ "$EUID" -ne 0 ] + then + echo " + This installer requires root permissions and will setup/uninstall + $APPNAME to run at system boot. The installer does the following: - if [ $INSTALL -ge 1 ] - then + * copy $APPNAME excutable to $BINPATH + * create configuration files in $SYSTEM_CONFIG_PATH + * setup systemd unit files in $SYSTEMD_UNIT_FILE_NAME + * add user "$APPNAME" to the GPIO and SPI access groups - # check if existing paperpi is installed - if [[ -d $INSTALLPATH ]] - then - echo "Removing existing installation found at $INSTALLPATH$APPNAME" - rm -rf $INSTALLPATH$APPNAME - fi + Try: + $ sudo $0 - if [ $UNINSTALL -gt 0 ] || [ $PURGE -gt 0 ] - then - echo "Removing files from $INSTALLPATH$APPNAME" - rm -rf $INSTALLPATH$APPNAME - fi + To uninstall or purge all files use: + $ $0 -u|-p + " + abort + fi + echo "Permissions OK" +} +function check_deb_packages { + if [ $INSTALL -lt 1 ] + then + # nothing to do here if not installing + echo "" + else + echo "Checking for required debian packages" + halt=0 - echo "Installing files to $INSTALLPATH$APPNAME" - rsync -a --exclude-from=$EXCLUDE --include-from=$INCLUDE $LOCALPATH $INSTALLPATH - cp $SCRIPT_DIR/../Pipfile $INSTALLPATH$APPNAME - fi + missing=() + # get all the debian_packages-*.txt + array=() + find $LOCALPATH -name "debian_packages-*.txt" -print0 >tmpfile + while IFS= read -r -d $'\0'; do + array+=("$REPLY") + done /dev/null; + then + echo "Paperpi user alreay exists" + else + useradd -m paperpi + echo "Created user 'paperpi'" + fi fi - popd - else - echo "" - fi + if [ $PURGE -gt 0 ] + then + echo "Purging paperpi user" + userdel -r paperpi + fi } -function check_deb_packages { - if [ $INSTALL -lt 1 ] +function copy_files { + + rsyncPath=$(dirname $INSTALLPATH) + if [ $INSTALL -ge 1 ] then - # nothing to do here if not installing - echo "" - else - echo "checking for required debian packages" - halt=0 - - missing=() - - # get all the debian_packages-*.txt - array=() - find $LOCALPATH -name "debian_packages-*.txt" -print0 >tmpfile - while IFS= read -r -d $'\0'; do - array+=("$REPLY") - done " - echo "" - cat $SCRIPT_DIR/requirements.txt - echo "" - echo "stopping install" - abort - fi + tempfile=$(mktemp) + # find all the requirements files + cat $SCRIPT_DIR/../requirements.txt > $tempfile + find $SCRIPT_DIR/../paperpi/plugins -type f -name "requirements-*.txt" -exec cat {} >> $tempfile \; + echo "Installing requirements from $tempfile" + cat $tempfile + $venvPath/bin/python -m pip install -r $tempfile + fi } - -# function check_py_packages { -# halt=0 -# missing=() - -# if [ $INSTALL -lt 1 ] -# then -# # nothing to do here for purge or uninstall -# echo "" -# else -# echo "checking python environment" -# echo "" -# source $SCRIPT_DIR/required_python_packages.txt -# for i in "${REQUIRED_PY[@]}" -# do -# echo "verifying python package $i" -# if ! pip3 show $i > /dev/null 2>&1 -# then -# echo "" -# echo "missing $i, attempting to install" -# echo "" -# pip3 install $i -# if pip3 show $i > /dev/null 2>&1 -# then -# echo "" -# echo "missing $i installed successfully. continuing..." -# echo "" -# else -# echo "" -# echo "automatic install of $i failed. Manual installation may be required" -# echo "" -# halt=$((halt+1)) -# missing+=( $i ) -# fi -# else -# echo "...OK" -# fi -# done -# fi - -# if [[ $halt -gt 0 ]] -# then -# echo "$halt required python packages are missing. See messages above." -# echo "install missing packages with:" -# echo "sudo pip3 install ${missing[*]}" -# echo "" -# echo "stopping install" -# abort -# fi -# } - function install_executable { if [ $INSTALL -gt 0 ] then - echo "adding executable to ${BINPATH}paperpi" - cp $SCRIPT_DIR/paperpi $BINPATH + echo "Adding executable to ${BINPATH}paperpi" + cp $SCRIPT_DIR/paperpi $BINPATH fi - if [ $UNINSTALL -gt 0 ] || [ $PURGE -gt 0 ] + if [ $UNINSTALL -gt 0 ] || [ $PURGE -gt 0 ] then - echo "removing excutable at ${BINPATH}paperpi" - rm ${BINPATH}paperpi + rm $BINPATH/paperpi fi } -function add_user { + +function install_config { if [ $INSTALL -gt 0 ] then - echo "adding user and group $APPNAME" - /usr/sbin/useradd --system $APPNAME - result=$? - if [ $result -ne 0 ] && [ $result -ne 9 ] - then - echo "failed to add user" - echo "install aborted" - abort - fi + echo "Installing system config" + INSTALL_CONFIG=0 - /usr/sbin/usermod -a -G spi,gpio $APPNAME - if [ $? -ne 0 ] + if [[ -f $SYSTEM_CONFIG_PATH ]] then - echo "failed to add user to groups: spi, gpio" - echo "install aborted" - abort + echo "########################################## +An existing config file found at $SYSTEM_CONFIG_PATH +Existing configuration files will not be overwritten + +A new version will be added at $SYSTEM_CONFIG_PATH.new +It may be useful to review the differences between the config files +Try: + $ diff $SYSTEM_CONFIG_PATH $SYSTEM_CONFIG_PATH.new +" + else + cp $SCRIPT_DIR/$CONFIG_FILE_NAME $SYSTEM_CONFIG_PATH fi fi if [ $PURGE -gt 0 ] then - echo "removing user and group: $APPNAME" - /usr/sbin/usermod -G $APPNAME $APPNAME - if [ $? -ne 0 ] + echo "Purging $SYSTEM_CONFIG_PATH" + if [ -f $SYSTEM_CONFIG_PATH ] then - echo faile to delete user $APPNAME - ERRORS=$((ERRORS+1)) + rm $SYSTEM_CONFIG_PATH + if [ $? -ne 0 ] + then + echo "failed to remove config file" + ERRORS=$((ERRORS+1)) + fi + else + echo "nothing to remove" fi fi } - function install_unit_file { if [ $INSTALL -eq 1 ] then @@ -415,47 +381,6 @@ function install_unit_file { fi } -function install_config { - if [ $INSTALL -gt 0 ] - then - echo "installing system config" - INSTALL_CONFIG=0 - - if [[ -f $SYSTEM_CONFIG_PATH ]] - then - echo "##############################################################" - echo "existing config files found at $SYSTEM_CONFIG_PATH" - echo "existing files will not be overwritten" - echo "" - echo "a new version will be added at $SYSTEM_CONFIG_PATH.new" - echo "it may be useful to review the differences between the config files" - echo "##############################################################" - cp $SCRIPT_DIR/$CONFIG_FILE_NAME $SYSTEM_CONFIG_PATH.new - - else - echo "adding config file: $SYSTEM_CONFIG_PATH" - cp $SCRIPT_DIR/$CONFIG_FILE_NAME $SYSTEM_CONFIG_PATH - fi - fi - - if [ $PURGE -gt 0 ] - then - echo "removing $SYSTEM_CONFIG_PATH" - if [ -f $SYSTEM_CONFIG_PATH ] - then - rm $SYSTEM_CONFIG_PATH - if [ $? -ne 0 ] - then - echo "failed to remove config file" - ERRORS=$((ERRORS+1)) - fi - else - echo "nothing to remove" - fi - fi -} - - function enable_spi { if [ $INSTALL -gt 0 ] then @@ -472,7 +397,6 @@ function enable_spi { fi } - function edit_config { if [ $INSTALL -gt 0 ] then @@ -538,11 +462,6 @@ function finish_install() then echo "uninstall completed" fi - - if [ $ERRORS -gt 0 ] - then - echo "$ERRORS errors occured, please see output above for details" - fi } @@ -555,53 +474,11 @@ function start_service { } -function check_permissions { - if [ "$EUID" -ne 0 ] - then - echo " - - Try: - $ sudo $0 - -This installer requires root permissions and will setup/uninstall -$APPNAME to run at system boot. The installer does the following: - - * copy $APPNAME excutable to $BINPATH - * create configuration files in $SYSTEM_CONFIG_PATH - * setup systemd unit files in $SYSTEMD_UNIT_FILE_NAME - * add user "$APPNAME" to the GPIO and SPI access groups - - To uninstall or purge all files use: - $ $0 -u|-p -" - exit 0 - fi -} - - - -function Help { - echo " - Install/Uninstall $APPNAME to run at boot - - This installer will install $APPNAME as a daemon service to - run at system startup. - - This installer must be run as root. - - options: - -h This help screen - -u uninstall $APPNAME - -p uninstall $APPNAME and purge all config files - -s skip OS version check for manuall install on 64 bit systems - " - -} - ## main program ## INSTALL=1 UNINSTALL=0 PURGE=0 +SKIP_OS_CHECK=0 while [[ $# -gt 0 ]]; do echo "processing $1" @@ -641,54 +518,13 @@ while [[ $# -gt 0 ]]; do esac done -ERRORS=0 - -if [ $PURGE -gt 0 ] -then - echo "WARNING all $APPNAME files will be removed including config files!" - echo "Proceed?" - read -p "n/Y " -n 1 -r - echo "" - - if [[ $REPLY =~ ^[Yy]$ ]] - then - PURGE=1 - else - PURGE=0 - echo "exiting..." - exit 0 - fi -fi - -# set the pipenv venv to be within the project directory (1) -export PIPENV_VENV_IN_PROJECT=1 - check_os stop_daemon check_permissions check_deb_packages -check_py_packages copy_files -if [ "$SKIP_OS_CHECK" -eq 1 ] -then - echo " " - printf "Basic install completed. You must now manually: - - create a pipenv in $INSTALLPATH/$APPNAME - - install development plugin requirements from the Pipfile in $INSTALLPATH/$APPNAME - - install the entry script in $BINPATH - - install the config in /etc/default - - install and enable the unit file (optional) - - enable SPI - - edit the config in /etc/defaults - - cleanup temporary files - - start the daemon (optional) -" - exit 0 -fi -create_pipenv -install_plugin_requirements +create_venv install_executable -add_user install_config install_unit_file enable_spi diff --git a/install/paperpi b/install/paperpi index 2d8ed20..564b6c8 100755 --- a/install/paperpi +++ b/install/paperpi @@ -3,15 +3,12 @@ # entry script to launch PaperPi PROGRAM_PATH=/usr/local/paperpi +VENV_PATH="$PROGRAM_PATH/venv_paperpi" -# set the pipenv venv within the project directory -export PIPENV_VENV_IN_PROJECT=1 +source "$VENV_PATH/bin/activate" -# set the location of the Pipfile -export PIPENV_PIPFILE=$(realpath $PROGRAM_PATH/Pipfile) +$(realpath $PROGRAM_PATH/paperpi.py "$@") -# launch paperpi in its pipenv-virtual environment -# pass all args sent to this script on to executable -pipenv run $(realpath $PROGRAM_PATH/paperpi.py) "$@" +deactivate diff --git a/install/signal.txt b/install/signal.txt deleted file mode 100644 index e69de29..0000000 diff --git a/install_waveshare_libs.sh b/install_waveshare_libs.sh deleted file mode 100755 index f7ecf9e..0000000 --- a/install_waveshare_libs.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -# wavehsare repo -WS_REPO="https://github.com/waveshare/e-Paper.git" -WS_ROOT="e-Paper" -WS_LIB_PATH="RaspberryPi_JetsonNano/python/lib/waveshare_epd" - -PROJECT="./paperpi/" -WS_LOCAL="$PROJECT/waveshare_epd" - -# git clone into temporary directory -WS_TEMP=$(mktemp -d -t waveshare_XXXXX) - -git clone $WS_REPO $WS_TEMP -if [[ $? -ne 0 ]]; -then - echo "failed to clone $WS_REPO" - echo "see $WS_TEMP" - exit 1 -fi - -WS_VERSION=$(git --git-dir $WS_TEMP/.git log -1 --format=%h\ %ci) -echo "this verison is: $WS_VERSION" - -rm -r $WS_LOCAL.ignore -mv $WS_LOCAL $WS_LOCAL.ignore -cp -r $WS_TEMP/$WS_LIB_PATH $PROJECT - -# # add the latest commit to the constants file for record keeping -sed -i "s#\(ws_version\s\?=\).*#\1 '$WS_VERSION'#g" $PROJECT/my_constants.py - -# ## Patch issues with WaveShare Modules ## -# # remove unneeded numpy imports in waveshare modules -# find $WS_LOCAL -type f -exec sed -i 's/^import numpy/#&/' {} \; - -# # add default value to `update` arg in init() method -echo "set update=false in init()" -find $WS_LOCAL -type f -exec sed -i -E 's/(^\W+def init\(self,\W+update)/\1=False/g' {} \; - -# # add default value to `color` arg in Clear() method (see epd2in7 for example) -# find $WS_LOCAL -type f -exec sed -i -E 's/(\W+def Clear\(self,\W+color)\)/\1=0xFF)/' {} \; - -# # default to full update in def init() for screens that support partial update -echo "set default lut value in init()" -find $WS_LOCAL -type f -exec sed -i -E 's/(def init\(self, lut)(.*)/\1=None\2\n if not lut:\n lut = self.lut_full_update/' {} \; diff --git a/paperpi/debian_packages-paperpi.txt b/paperpi/debian_packages-paperpi.txt index 93dc949..924be55 100644 --- a/paperpi/debian_packages-paperpi.txt +++ b/paperpi/debian_packages-paperpi.txt @@ -1,2 +1,3 @@ # core debian packages required for paperpi to function properly -DEBPKG=( "libtiff5" "libopenjp2-7" "python3-pip" "libatlas-base-dev" "libjpeg-dev") +# DEBPKG=( "libtiff-dev" "libopenjp2-7" "python3-pip" "libatlas-base-dev" "libjpeg-dev" "cython3" ) +DEBPKG=( "libtiff-dev" "libopenjp2-7" "python3-pip" "python3-venv" ) diff --git a/paperpi/waveshare_epd/epd13in3k.py b/paperpi/waveshare_epd/epd13in3k.py new file mode 100644 index 0000000..d097907 --- /dev/null +++ b/paperpi/waveshare_epd/epd13in3k.py @@ -0,0 +1,187 @@ +# ***************************************************************************** +# * | File : epd7in5.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V4.0 +# * | Date : 2019-06-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 960 +EPD_HEIGHT = 680 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.SPI.writebytes2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 1): + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x0C) + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0x80) + + self.send_command(0x01) + self.send_data(0xA7) + self.send_data(0x02) + self.send_data(0x00) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) # X-mode + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xBF) + self.send_data(0x03) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xA7) + self.send_data(0x02) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x05) + + self.send_command(0x18) # use the internal temperature sensor + self.send_data(0x80) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + # EPD hardware init end + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.TurnOnDisplay() + + def Clear(self): + buf = [0xFF] * (int(self.width/8) * self.height) + self.send_command(0x24) + self.send_data2(buf) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### diff --git a/paperpi/waveshare_epd/epd2in13_V4.py b/paperpi/waveshare_epd/epd2in13_V4.py new file mode 100644 index 0000000..a9fd210 --- /dev/null +++ b/paperpi/waveshare_epd/epd2in13_V4.py @@ -0,0 +1,350 @@ +# ***************************************************************************** +# * | File : epd2in13_V4.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-06-25 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import logging +from . import epdconfig + +# Display resolution +EPD_WIDTH = 122 +EPD_HEIGHT = 250 + +logger = logging.getLogger(__name__) + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + ''' + function :Hardware reset + parameter: + ''' + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + ''' + function :send command + parameter: + command : Command register + ''' + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + ''' + function :send data + parameter: + data : Write data + ''' + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + ''' + function :Wait until the busy_pin goes LOW + parameter: + ''' + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(10) + logger.debug("e-Paper busy release") + + ''' + function : Turn On Display + parameter: + ''' + def TurnOnDisplay(self): + self.send_command(0x22) # Display Update Control + self.send_data(0xf7) + self.send_command(0x20) # Activate Display Update Sequence + self.ReadBusy() + + ''' + function : Turn On Display Fast + parameter: + ''' + def TurnOnDisplay_Fast(self): + self.send_command(0x22) # Display Update Control + self.send_data(0xC7) # fast:0x0c, quality:0x0f, 0xcf + self.send_command(0x20) # Activate Display Update Sequence + self.ReadBusy() + + ''' + function : Turn On Display Part + parameter: + ''' + def TurnOnDisplayPart(self): + self.send_command(0x22) # Display Update Control + self.send_data(0xff) # fast:0x0c, quality:0x0f, 0xcf + self.send_command(0x20) # Activate Display Update Sequence + self.ReadBusy() + + + ''' + function : Setting the display window + parameter: + xstart : X-axis starting position + ystart : Y-axis starting position + xend : End position of X-axis + yend : End position of Y-axis + ''' + def SetWindow(self, x_start, y_start, x_end, y_end): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + # x point must be the multiple of 8 or the last 3 bits will be ignored + self.send_data((x_start>>3) & 0xFF) + self.send_data((x_end>>3) & 0xFF) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(y_start & 0xFF) + self.send_data((y_start >> 8) & 0xFF) + self.send_data(y_end & 0xFF) + self.send_data((y_end >> 8) & 0xFF) + + ''' + function : Set Cursor + parameter: + x : X-axis starting position + y : Y-axis starting position + ''' + def SetCursor(self, x, y): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + # x point must be the multiple of 8 or the last 3 bits will be ignored + self.send_data(x & 0xFF) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(y & 0xFF) + self.send_data((y >> 8) & 0xFF) + + ''' + function : Initialize the e-Paper register + parameter: + ''' + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data(0xf9) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.SetWindow(0, 0, self.width-1, self.height-1) + self.SetCursor(0, 0) + + self.send_command(0x3c) + self.send_data(0x05) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x80) + + self.send_command(0x18) + self.send_data(0x80) + + self.ReadBusy() + + return 0 + + ''' + function : Initialize the e-Paper fast register + parameter: + ''' + def init_fast(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x18) # Read built-in temperature sensor + self.send_command(0x80) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) + + self.SetWindow(0, 0, self.width-1, self.height-1) + self.SetCursor(0, 0) + + self.send_command(0x22) # Load temperature value + self.send_data(0xB1) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x1A) # Write to temperature register + self.send_data(0x64) + self.send_data(0x00) + + self.send_command(0x22) # Load temperature value + self.send_data(0x91) + self.send_command(0x20) + self.ReadBusy() + + return 0 + ''' + function : Display images + parameter: + image : Image data + ''' + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + # image has correct dimensions, but needs to be rotated + img = img.rotate(90, expand=True).convert('1') + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return [0x00] * (int(self.width/8) * self.height) + + buf = bytearray(img.tobytes('raw')) + return buf + + ''' + function : Sends the image buffer in RAM to e-Paper and displays + parameter: + image : Image data + ''' + def display(self, image): + self.send_command(0x24) + self.send_data2(image) + self.TurnOnDisplay() + + ''' + function : Sends the image buffer in RAM to e-Paper and fast displays + parameter: + image : Image data + ''' + def display_fast(self, image): + self.send_command(0x24) + self.send_data2(image) + self.TurnOnDisplay_Fast() + ''' + function : Sends the image buffer in RAM to e-Paper and partial refresh + parameter: + image : Image data + ''' + def displayPartial(self, image): + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(1) + epdconfig.digital_write(self.reset_pin, 1) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x80) + + self.send_command(0x01) # Driver output control + self.send_data(0xF9) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) + + self.SetWindow(0, 0, self.width - 1, self.height - 1) + self.SetCursor(0, 0) + + self.send_command(0x24) # WRITE_RAM + self.send_data2(image) + self.TurnOnDisplayPart() + + ''' + function : Refresh a base image + parameter: + image : Image data + ''' + def displayPartBaseImage(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + self.TurnOnDisplay() + + ''' + function : Clear screen + parameter: + ''' + def Clear(self, color=0xFF): + if self.width%8 == 0: + linewidth = int(self.width/8) + else: + linewidth = int(self.width/8) + 1 + # logger.debug(linewidth) + + self.send_command(0x24) + self.send_data2([color] * int(self.height * linewidth)) + self.TurnOnDisplay() + + ''' + function : Enter sleep mode + parameter: + ''' + def sleep(self): + self.send_command(0x10) #enter deep sleep + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/paperpi/waveshare_epd/epd2in9_V2.py b/paperpi/waveshare_epd/epd2in9_V2.py index 8256c88..d67ea0a 100644 --- a/paperpi/waveshare_epd/epd2in9_V2.py +++ b/paperpi/waveshare_epd/epd2in9_V2.py @@ -33,6 +33,10 @@ # Display resolution EPD_WIDTH = 128 EPD_HEIGHT = 296 +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest logger = logging.getLogger(__name__) @@ -44,6 +48,10 @@ def __init__(self): self.cs_pin = epdconfig.CS_PIN self.width = EPD_WIDTH self.height = EPD_HEIGHT + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest WF_PARTIAL_2IN9 = [ 0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, @@ -89,6 +97,28 @@ def __init__(self): 0x22, 0x17, 0x41, 0x0, 0x32, 0x36 ] + Gray4 = [ + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, + 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, + 0x22, 0x17, 0x41, 0xAE, 0x32, 0x28 + ] + # Hardware reset def reset(self): epdconfig.digital_write(self.reset_pin, 1) @@ -204,6 +234,36 @@ def init(self): self.SetLut(self.WS_20_30) # EPD hardware init end return 0 + + def Init_4Gray(self): + if (epdconfig.module_init() != 0): + return -1 + self.reset() + epdconfig.delay_ms(100) + + self.ReadBusy() + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x01) #Driver output control + self.send_data(0x27) + self.send_data(0x01) + self.send_data(0x00) + + self.send_command(0x11) #data entry mode + self.send_data(0x03) + + self.SetWindow(8, 0, self.width, self.height-1) + + self.send_command(0x3C) + self.send_data(0x04) + + self.SetCursor(1, 0) + self.ReadBusy() + + self.SetLut(self.Gray4) + # EPD hardware init end + return 0 def getbuffer(self, image): # logger.debug("bufsiz = ",int(self.width/8) * self.height) @@ -228,6 +288,42 @@ def getbuffer(self, image): if pixels[x, y] == 0: buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf def display(self, image): if (image == None): @@ -247,6 +343,73 @@ def display_Base(self, image): self.send_data2(image) self.TurnOnDisplay() + + def display_4Gray(self, image): + self.send_command(0x24) + for i in range(0, 4736): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else: #0x40 + temp3 |= 0x00 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x01 + else : #0x40 + temp3 |= 0x00 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x26) + for i in range(0, 4736): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x00 + elif(temp2 == 0x00): + temp3 |= 0x01 + elif(temp2 == 0x80): + temp3 |= 0x00 + else: #0x40 + temp3 |= 0x01 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.TurnOnDisplay() def display_Partial(self, image): if (image == None): @@ -285,6 +448,7 @@ def display_Partial(self, image): self.send_data2(image) self.TurnOnDisplay_Partial() + def Clear(self, color=0xFF): if self.width%8 == 0: linewidth = int(self.width/8) @@ -294,6 +458,9 @@ def Clear(self, color=0xFF): self.send_command(0x24) # WRITE_RAM self.send_data2([color] * int(self.height * linewidth)) self.TurnOnDisplay() + self.send_command(0x26) # WRITE_RAM + self.send_data2([color] * int(self.height * linewidth)) + self.TurnOnDisplay() def sleep(self): self.send_command(0x10) # DEEP_SLEEP_MODE diff --git a/paperpi/waveshare_epd/epd4in2_V2.py b/paperpi/waveshare_epd/epd4in2_V2.py new file mode 100644 index 0000000..105d57b --- /dev/null +++ b/paperpi/waveshare_epd/epd4in2_V2.py @@ -0,0 +1,530 @@ +# ***************************************************************************** +# * | File : epd4in2_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2023-09-13 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import logging +from . import epdconfig +from PIL import Image +import RPi.GPIO as GPIO + +# Display resolution +EPD_WIDTH = 400 +EPD_HEIGHT = 300 + +GRAY1 = 0xff # white +GRAY2 = 0xC0 +GRAY3 = 0x80 # gray +GRAY4 = 0x00 # Blackest + +logger = logging.getLogger(__name__) + + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + self.Seconds_1_5S = 0 + self.Seconds_1S = 1 + self.GRAY1 = GRAY1 # white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 # gray + self.GRAY4 = GRAY4 # Blackest + + + LUT_ALL=[ 0x01, 0x0A, 0x1B, 0x0F, 0x03, 0x01, 0x01, + 0x05, 0x0A, 0x01, 0x0A, 0x01, 0x01, 0x01, + 0x05, 0x08, 0x03, 0x02, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x0A, 0x1B, 0x0F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x03, 0x82, 0x84, 0x01, 0x01, + 0x01, 0x84, 0x84, 0x82, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x0A, 0x1B, 0x8F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x83, 0x82, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x8A, 0x1B, 0x8F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x83, 0x02, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x8A, 0x9B, 0x8F, 0x03, 0x01, 0x01, + 0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01, + 0x05, 0x48, 0x03, 0x42, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x42, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x07, 0x17, 0x41, 0xA8, + 0x32, 0x30 ] + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(100) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(100) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xF7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Fast(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xC7) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_Partial(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xFF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def TurnOnDisplay_4GRAY(self): + self.send_command(0x22) #Display Update Control + self.send_data(0xCF) + self.send_command(0x20) #Activate Display Update Sequence + self.ReadBusy() + + def init(self): + if epdconfig.module_init() != 0: + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x21) # Display update control + self.send_data(0x40) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x05) + + self.send_command(0x11) # data entry mode + self.send_data(0x03) # X-mode + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def init_fast(self, mode): + if epdconfig.module_init() != 0: + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x21) # Display update control + self.send_data(0x40) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x05) + + if mode == self.Seconds_1_5S: + self.send_command(0x1A) + self.send_data(0x6E) + else : + self.send_command(0x1A) + self.send_data(0x5A) + + self.send_command(0x22) # Load temperature value + self.send_data(0x91) + self.send_command(0x20) + self.ReadBusy() + + self.send_command(0x11) # data entry mode + self.send_data(0x03) # X-mode + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def Lut(self): + self.send_command(0x32) + for i in range(227): + self.send_data(self.LUT_ALL[i]) + + self.send_command(0x3F) + self.send_data(self.LUT_ALL[227]) + + self.send_command(0x03) + self.send_data(self.LUT_ALL[228]) + + self.send_command(0x04) + self.send_data(self.LUT_ALL[229]) + self.send_data(self.LUT_ALL[230]) + self.send_data(self.LUT_ALL[231]) + + self.send_command(0x2c) + self.send_data(self.LUT_ALL[232]) + + + + def Init_4Gray(self): + if epdconfig.module_init() != 0: + return -1 + # EPD hardware init start + self.reset() + self.ReadBusy() + + self.send_command(0x12) #SWRESET + self.ReadBusy() + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x03) + + self.send_command(0x0C) # BTST + self.send_data(0x8B) # 8B + self.send_data(0x9C) # 9C + self.send_data(0xA4) # 96 A4 + self.send_data(0x0F) # 0F + + self.Lut() + + self.send_command(0x11) # data entry mode + self.send_data(0x03) # X-mode + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif imwidth == self.height and imheight == self.width: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i = 0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if imwidth == self.width and imheight == self.height: + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0xC0: + pixels[x, y] = 0x80 + elif pixels[x, y] == 0x80: + pixels[x, y] = 0x40 + i = i + 1 + if i % 4 == 0: + buf[int((x + (y * self.width)) / 4)] = ( + (pixels[x - 3, y] & 0xc0) | (pixels[x - 2, y] & 0xc0) >> 2 | ( + pixels[x - 1, y] & 0xc0) >> 4 | (pixels[x, y] & 0xc0) >> 6) + + elif imwidth == self.height and imheight == self.width: + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = x + if pixels[x, y] == 0xC0: + pixels[x, y] = 0x80 + elif pixels[x, y] == 0x80: + pixels[x, y] = 0x40 + i = i + 1 + if i % 4 == 0: + buf[int((newx + (newy * self.width)) / 4)] = ( + (pixels[x, y - 3] & 0xc0) | (pixels[x, y - 2] & 0xc0) >> 2 | ( + pixels[x, y - 1] & 0xc0) >> 4 | (pixels[x, y] & 0xc0) >> 6) + + return buf + + def Clear(self): + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + + self.send_command(0x24) + self.send_data2([0xff] * int(self.height * linewidth)) + + self.send_command(0x26) + self.send_data2([0xff] * int(self.height * linewidth)) + + self.TurnOnDisplay() + + def display(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + + self.TurnOnDisplay() + + def display_Fast(self, image): + self.send_command(0x24) + self.send_data2(image) + + self.send_command(0x26) + self.send_data2(image) + + self.TurnOnDisplay_Fast() + + def display_Partial(self, Image): + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x80) + + self.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x80) + + self.send_command(0x44) + self.send_data(0x00) + self.send_data(0x31) + + self.send_command(0x45) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x2B) + self.send_data(0x01) + + self.send_command(0x4E) + self.send_data(0x00) + + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x24) # WRITE_RAM + self.send_data2(Image) + self.TurnOnDisplay_Partial() + + def display_4Gray(self, image): + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + + buf = [0x00] * self.height * linewidth + + self.send_command(0x24) + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): # EPD_WIDTH * EPD_HEIGHT / 4 + temp3 = 0 + for j in range(0, 2): + temp1 = image[i * 2 + j] + for k in range(0, 2): + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: + temp3 |= 0x01 # white + elif temp2 == 0x00: + temp3 |= 0x00 # black + elif temp2 == 0x80: + temp3 |= 0x00 # gray1 + else: # 0x40 + temp3 |= 0x01 # gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: # white + temp3 |= 0x01 + elif temp2 == 0x00: # black + temp3 |= 0x00 + elif temp2 == 0x80: + temp3 |= 0x00 # gray1 + else: # 0x40 + temp3 |= 0x01 # gray2 + if j != 1 or k != 1: + temp3 <<= 1 + temp1 <<= 2 + buf[i] = temp3 + self.send_data2(buf) + + self.send_command(0x26) + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): + temp3 = 0 + for j in range(0, 2): + temp1 = image[i * 2 + j] + for k in range(0, 2): + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: + temp3 |= 0x01 # white + elif temp2 == 0x00: + temp3 |= 0x00 # black + elif temp2 == 0x80: + temp3 |= 0x01 # gray1 + else: # 0x40 + temp3 |= 0x00 # gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1 & 0xC0 + if temp2 == 0xC0: # white + temp3 |= 0x01 + elif temp2 == 0x00: # black + temp3 |= 0x00 + elif temp2 == 0x80: + temp3 |= 0x01 # gray1 + else: # 0x40 + temp3 |= 0x00 # gray2 + if j != 1 or k != 1: + temp3 <<= 1 + temp1 <<= 2 + buf[i] = temp3 + self.send_data2(buf) + + self.TurnOnDisplay_4GRAY() + # pass + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### diff --git a/paperpi/waveshare_epd/epdconfig.py b/paperpi/waveshare_epd/epdconfig.py index f692f43..fa2be6a 100644 --- a/paperpi/waveshare_epd/epdconfig.py +++ b/paperpi/waveshare_epd/epdconfig.py @@ -230,7 +230,7 @@ def module_exit(self): self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN], self.PWR_PIN) -if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'): +if os.path.exists('/etc/issue'): implementation = RaspberryPi() elif os.path.exists('/sys/bus/platform/drivers/gpio-x3'): implementation = SunriseX3() diff --git a/paperpi/waveshare_epd/epdconfig.py_bak b/paperpi/waveshare_epd/epdconfig.py_bak new file mode 100644 index 0000000..f692f43 --- /dev/null +++ b/paperpi/waveshare_epd/epdconfig.py_bak @@ -0,0 +1,243 @@ +# /***************************************************************************** +# * | File : epdconfig.py +# * | Author : Waveshare team +# * | Function : Hardware underlying interface +# * | Info : +# *---------------- +# * | This version: V1.2 +# * | Date : 2022-10-29 +# * | Info : +# ****************************************************************************** +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +import os +import logging +import sys +import time + +logger = logging.getLogger(__name__) + + +class RaspberryPi: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + PWR_PIN = 18 + + def __init__(self): + import spidev + import RPi.GPIO + + self.GPIO = RPi.GPIO + self.SPI = spidev.SpiDev() + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(pin) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.writebytes(data) + + def spi_writebyte2(self, data): + self.SPI.writebytes2(data) + + def module_init(self): + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) + self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) + + self.GPIO.output(self.PWR_PIN, 1) + + # SPI device, bus = 0, device = 0 + self.SPI.open(0, 0) + self.SPI.max_speed_hz = 4000000 + self.SPI.mode = 0b00 + return 0 + + def module_exit(self): + logger.debug("spi end") + self.SPI.close() + + logger.debug("close 5V, Module enters 0 power consumption ...") + self.GPIO.output(self.RST_PIN, 0) + self.GPIO.output(self.DC_PIN, 0) + self.GPIO.output(self.PWR_PIN, 0) + + self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN, self.PWR_PIN]) + + +class JetsonNano: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + PWR_PIN = 18 + + def __init__(self): + import ctypes + find_dirs = [ + os.path.dirname(os.path.realpath(__file__)), + '/usr/local/lib', + '/usr/lib', + ] + self.SPI = None + for find_dir in find_dirs: + so_filename = os.path.join(find_dir, 'sysfs_software_spi.so') + if os.path.exists(so_filename): + self.SPI = ctypes.cdll.LoadLibrary(so_filename) + break + if self.SPI is None: + raise RuntimeError('Cannot find sysfs_software_spi.so') + + import Jetson.GPIO + self.GPIO = Jetson.GPIO + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(self.BUSY_PIN) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.SYSFS_software_spi_transfer(data[0]) + + def spi_writebyte2(self, data): + for i in range(len(data)): + self.SPI.SYSFS_software_spi_transfer(data[i]) + + def module_init(self): + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) + self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) + + self.GPIO.output(self.PWR_PIN, 1) + + self.SPI.SYSFS_software_spi_begin() + return 0 + + def module_exit(self): + logger.debug("spi end") + self.SPI.SYSFS_software_spi_end() + + logger.debug("close 5V, Module enters 0 power consumption ...") + self.GPIO.output(self.RST_PIN, 0) + self.GPIO.output(self.DC_PIN, 0) + self.GPIO.output(self.PWR_PIN, 0) + + self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN, self.PWR_PIN]) + + +class SunriseX3: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + PWR_PIN = 18 + Flag = 0 + + def __init__(self): + import spidev + import Hobot.GPIO + + self.GPIO = Hobot.GPIO + self.SPI = spidev.SpiDev() + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(pin) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.writebytes(data) + + def spi_writebyte2(self, data): + # for i in range(len(data)): + # self.SPI.writebytes([data[i]]) + self.SPI.xfer3(data) + + def module_init(self): + if self.Flag == 0: + self.Flag = 1 + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) + self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) + + self.GPIO.output(self.PWR_PIN, 1) + + # SPI device, bus = 0, device = 0 + self.SPI.open(2, 0) + self.SPI.max_speed_hz = 4000000 + self.SPI.mode = 0b00 + return 0 + else: + return 0 + + def module_exit(self): + logger.debug("spi end") + self.SPI.close() + + logger.debug("close 5V, Module enters 0 power consumption ...") + self.Flag = 0 + self.GPIO.output(self.RST_PIN, 0) + self.GPIO.output(self.DC_PIN, 0) + self.GPIO.output(self.PWR_PIN, 0) + + self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN], self.PWR_PIN) + + +if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'): + implementation = RaspberryPi() +elif os.path.exists('/sys/bus/platform/drivers/gpio-x3'): + implementation = SunriseX3() +else: + implementation = JetsonNano() + +for func in [x for x in dir(implementation) if not x.startswith('_')]: + setattr(sys.modules[__name__], func, getattr(implementation, func)) + +### END OF FILE ### diff --git a/paperpi/plugins/crypto/README.md b/plugins_depricated/crypto/README.md similarity index 100% rename from paperpi/plugins/crypto/README.md rename to plugins_depricated/crypto/README.md diff --git a/paperpi/plugins/crypto/README_additional.md b/plugins_depricated/crypto/README_additional.md similarity index 100% rename from paperpi/plugins/crypto/README_additional.md rename to plugins_depricated/crypto/README_additional.md diff --git a/paperpi/plugins/crypto/__init__.py b/plugins_depricated/crypto/__init__.py similarity index 100% rename from paperpi/plugins/crypto/__init__.py rename to plugins_depricated/crypto/__init__.py diff --git a/paperpi/plugins/crypto/constants.py b/plugins_depricated/crypto/constants.py similarity index 100% rename from paperpi/plugins/crypto/constants.py rename to plugins_depricated/crypto/constants.py diff --git a/paperpi/plugins/crypto/crypto.ipynb b/plugins_depricated/crypto/crypto.ipynb similarity index 100% rename from paperpi/plugins/crypto/crypto.ipynb rename to plugins_depricated/crypto/crypto.ipynb diff --git a/paperpi/plugins/crypto/crypto.layout-L-sample.png b/plugins_depricated/crypto/crypto.layout-L-sample.png similarity index 100% rename from paperpi/plugins/crypto/crypto.layout-L-sample.png rename to plugins_depricated/crypto/crypto.layout-L-sample.png diff --git a/paperpi/plugins/crypto/crypto.py b/plugins_depricated/crypto/crypto.py similarity index 100% rename from paperpi/plugins/crypto/crypto.py rename to plugins_depricated/crypto/crypto.py diff --git a/paperpi/plugins/crypto/crypto.ticker_hd-L-sample.png b/plugins_depricated/crypto/crypto.ticker_hd-L-sample.png similarity index 100% rename from paperpi/plugins/crypto/crypto.ticker_hd-L-sample.png rename to plugins_depricated/crypto/crypto.ticker_hd-L-sample.png diff --git a/paperpi/plugins/crypto/crypto.ticker_simple-L-sample.png b/plugins_depricated/crypto/crypto.ticker_simple-L-sample.png similarity index 100% rename from paperpi/plugins/crypto/crypto.ticker_simple-L-sample.png rename to plugins_depricated/crypto/crypto.ticker_simple-L-sample.png diff --git a/paperpi/plugins/crypto/debian_packages-crypto.txt b/plugins_depricated/crypto/debian_packages-crypto.txt similarity index 100% rename from paperpi/plugins/crypto/debian_packages-crypto.txt rename to plugins_depricated/crypto/debian_packages-crypto.txt diff --git a/paperpi/plugins/crypto/images/unknown.png b/plugins_depricated/crypto/images/unknown.png similarity index 100% rename from paperpi/plugins/crypto/images/unknown.png rename to plugins_depricated/crypto/images/unknown.png diff --git a/paperpi/plugins/crypto/layout.py b/plugins_depricated/crypto/layout.py similarity index 100% rename from paperpi/plugins/crypto/layout.py rename to plugins_depricated/crypto/layout.py diff --git a/paperpi/plugins/crypto/requirements-crypto.txt b/plugins_depricated/crypto/requirements-crypto.txt similarity index 100% rename from paperpi/plugins/crypto/requirements-crypto.txt rename to plugins_depricated/crypto/requirements-crypto.txt diff --git a/paperpi/plugins/crypto/requirements-crypto_hidden.txt b/plugins_depricated/crypto/requirements-crypto_hidden.txt similarity index 100% rename from paperpi/plugins/crypto/requirements-crypto_hidden.txt rename to plugins_depricated/crypto/requirements-crypto_hidden.txt diff --git a/paperpi/plugins/crypto/sample.py b/plugins_depricated/crypto/sample.py similarity index 100% rename from paperpi/plugins/crypto/sample.py rename to plugins_depricated/crypto/sample.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f2b2935 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +-i https://www.piwheels.org/simple/ +--extra-index-url https://www.pypi.org/simple +argconfigparse +epdlib +git+https://github.com/GregDMeyer/IT8951.git +pillow +rpi.gpio +spidev diff --git a/utilities/create_devel_environment.sh b/utilities/create_devel_environment.sh deleted file mode 100755 index 085a6fa..0000000 --- a/utilities/create_devel_environment.sh +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/env bash - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -PROJECT_DIR=$(dirname $SCRIPT_DIR) -PYVERSION="python 3" - -function abort { - # abort installation with message - printf "%s\n" "$@" - printf "%s\n\nThis installer can be resumed with:\n" - printf "sudo $SCRIPT_DIR/$(basename "$0")\n" - exit 1 -} - -function check_system { - echo "checking if SPI is enabled" - echo "" - if [[ $(sudo raspi-config nonint get_spi) = "1" ]] - then - echo "" - echo "SPI is not enabled and is required for PaperPi to function" - echo "enable with:" - echo "$ sudo raspi-config nonint do_spi 0" - echo "exiting" - exit 0 - else - echo "SPI OK" - fi -} - -function check_deb_packages { - - if [ $INSTALL -lt 1 ] - then - # nothing to do here if not installing - echo "" - else - echo "checking for required debian packages" - halt=0 - - missing=() - - # get all the debian_packages-*.txt - array=() - find $PROJECT_DIR -name "debian_packages-*.txt" -print0 >tmpfile - while IFS= read -r -d $'\0'; do - array+=("$REPLY") - done > $tempfile \; - echo "Installing development dependencies for all plugins:" - cat $tempfile - pushd $PROJECT_DIR > /dev/null 2>&1 - # add all the modules from the plugins - echo "tempfile: $tempfile" - pipenv install --dev -r $tempfile - popd > /dev/null 2>&1 - fi -} - -function add_kernel() { - if [ $JUPYTER -gt 0 ] - then - venvDir=$(pipenv --venv) - projectName=$(basename $venvDir) - echo "installing ipykernel module" - pipenv install --dev ipykernel - echo "adding kernel spec: $projectName" - pipenv run python -m ipykernel install --user --name="${projectName}" - fi -} - -function clean_devel_modules { - # clean development modules and start fresh - if [ $INSTALL -gt 0 ] - then - echo "removing all previous development modules" - pushd $PROJECT_DIR > /dev/null 2>&1 - pipenv uninstall --all-dev - popd > /dev/null 2>&1 - fi -} - -function rm_venv { - # completely remove pipenv - if [ $PURGE -gt 0 ] - then - echo "removing pipenv virtual environment" - pushd $SCRIPT_DIR/../ > /dev/null 2>&1 - pipenv --rm - popd > /dev/null 2>&1 - fi -} - -function clean_kernel() { - if [ $PURGE -gt 0 ] - then - venvDir=$(pipenv --venv) - venvName=$(basename $venvDir| tr '[:upper:]' '[:lower:]') - jupyter kernelspec remove $venvName $venvName - fi -} - -function Help { - echo " - Create a development environment for this project - - usage: - $ $0 option - - options: - -c: create the virtual environment - -j: create the virtual environment and add jupyter kernel - -h: This help screen - -p: purge the virtual environment - --info: virtual environment information - -" -exit 0 -} - -function venv_info { - echo "Pipenv Information:" - pushd $SCRIPT_DIR/../ > /dev/null 2>&1 - pipenv graph - pipenv --venv - exit 0 -} - - -## main program ## -INSTALL=0 -PURGE=0 -JUPYTER=0 - - -while [[ $# -gt 0 ]]; do - case $1 in - -h) - Help - exit - shift - shift - ;; - -c) - INSTALL=1 - PURGE=0 - shift - shift - ;; - -j) - INSTALL=1 - PURGE=0 - JUPYTER=1 - shift - shift - ;; - -p) - PURGE=1 - INSTALL=0 - shift - shift - ;; - - --info) - venv_info - exit 0 - ;; - -*) - echo "unknown option: $1" - echo "" - Help - exit - ;; - *) - shift - ;; - esac -done - -if [[ $INSTALL -eq 0 ]] && [[ $PURGE -eq 0 ]]; then - Help -fi - -# fail fast for required software - -if ! command pip3 > /dev/null 2>&1 -then - echo "pip3 is not installed and is required for this development enviornment" - echo "try: - sudo apt install python3-pip - " - exit -fi - -if ! command pipenv > /dev/null 2>&1 -then - echo "pipenv is not installed and is required for this development environment" - echo "try: - pip3 install pipenv - -for a system-wide install try: - sudo pip3 install pipenv - " - exit 1 -fi - -# check if jupyter is installed -! command jupyter > /dev/null 2>&1 -JUPY_RESULT=$? - -if [[ $JUPY_RESULT>0 && $JUPYTER==1 ]] -then - echo "jupyter is not installed and is required with the '-j' switch" - echo "try: - pip3 install jupyter" -fi - - -check_system -check_deb_packages -clean_devel_modules -install_devel_requirements -add_kernel -clean_kernel -rm_venv - diff --git a/utilities/debian_packages-jupyter_devel.txt b/utilities/debian_packages-jupyter_devel.txt new file mode 100644 index 0000000..e21e233 --- /dev/null +++ b/utilities/debian_packages-jupyter_devel.txt @@ -0,0 +1 @@ +DEBPKG=( "jupyter" ) diff --git a/utilities/init_devel_environment.sh b/utilities/init_devel_environment.sh new file mode 100755 index 0000000..d88db5f --- /dev/null +++ b/utilities/init_devel_environment.sh @@ -0,0 +1,310 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +PROJECT_DIR=$(dirname $SCRIPT_DIR) + +# get the currently installed python version +PY_VERSION=$(python3 -c 'import sys; print("{}.{}".format(sys.version_info.major, sys.version_info.minor))') +PY_MAJOR=$(echo "$PY_VERSION" | cut -d. -f1) +PY_MINOR=$(echo "$PY_VERSION" | cut -d. -f2) + +# virtual environment name +VENV_HASH=$(echo -n "$PROJECT_DIR" | md5sum | cut -c1-10) +VENV=$PROJECT_DIR/venv_paperpi-$VENV_HASH + +# options and packages required for jupyter +# jupyter debian packages +JUPYTER_DPKG="$PROJECT_DIR/utilities/debian_packages-jupyter_devel.txt" +# jupyter python modules +JUPYTER_MODS=( "jupytext" ) + + + +function abort { + # abort installation with message + printf "%s\n" "$@" + printf "%s\n\nThis installer can be resumed with:\n" + printf "sudo $SCRIPT_DIR/$(basename "$0")\n" + exit 1 +} + +function Help { + echo " + Create a development environment for this project + + usage: + $ $0 [option] + + options: + -c: create the virtual environment + -j: create the virtual environment and add jupyter kernel + -h: This help screen + -p: purge the virtual environment and clean up kernel specs + --info: virtual environment information + +" +exit 0 +} + +# check for underlying debian packages required for development +function check_deb_system { + + CHECK_PATH="$PROJECT_DIR/paperpi" + find "$CHECK_PATH" -name "debian_packages-*.txt" >>tmpfile + mapfile -t array < tmpfile + rm -f tmpfile + + if [ $INSTALL -lt 1 ] + then + uninstall=() + echo "The following pakcages MAY have been installed during the environment init:" + for i in "${array[@]}" + do + source "${i}" + for i in "${DEBPKG[@]}" + do + echo "$i" + uninstall+=($i) + done + done + + echo " +Packages can be removed AT YOUR OWN RISK using:" + echo " $ apt remove ${uninstall[@]}" + echo " +NOTE: Some of these packages may have already existed on your system or may be required by other programs. +Remove them at your own risk!" + + return + fi + + echo "Locating required debian system packages in $CHECK_PATH" + + halt=0 + missing=() + # get all files that match debian_packages-*.txt + + + if [ $JUPYTER -gt 0 ] + then + array+=( $JUPYTER_DPKG ) + fi + + for i in "${array[@]}" + do + echo "Checking debian system packages for PaperPi found in: '$(basename $i)'" + source "${i}" + for i in "${DEBPKG[@]}" + do + echo "checking $i" + if [ $(dpkg-query -W -f='${Status}' $i | grep -c "ok installed") -eq 0 ] + then + echo "" + echo "missing $i" + echo "" + halt=$((halt+1)) + missing+=( $i ) + else + echo "$i OK" + + fi + done + done + + if [[ $halt -gt 0 ]] + then + echo "$halt required packages are missing. + install missing packages with: + + $ sudo apt install ${missing[*]} + + stopping install" + abort + else + echo "All required debian system packages are installed" + fi + +} + +# check that SPI is enabled +function check_spi { + if [ $INSTALL -lt 1 ] + then + # nothing to do here if not installing + echo "" + else + echo "Checking for SPI" + if [[ $(sudo raspi-config nonint get_spi) = "1" ]] + then + echo "" + echo "SPI is not enabled and is required for PaperPi to function" + echo "enable with:" + echo "$ sudo raspi-config nonint do_spi 0" + abort + else + echo "SPI OK" + fi + fi +} + +# create a virtual environment to work in +# add jupyter essentials if asked +function create_venv { + venvName=$(basename $VENV) + + if [ $INSTALL -gt 0 ] + then + echo "Creating virtual environment in $VENV" + if [ -f $VENV/bin/activate ] + then + echo "Virtual environment in $VENV exists" + else + pushd $PROJECT_DIR + python3 -m venv $VENV + popd + ln -s $VENV/bin/activate $PROJECT_DIR/venv_activate + fi + + echo "Installing development requirements" + tempfile=$(mktemp) + cat $PROJECT_DIR/requirements.txt > $tempfile + + cat $PROJECT_DIR/utilities/requirements-devel.txt >> $tempfile + + if [ $JUPYTER -gt 0 ] + then + cat $PROJECT_DIR/utilities/requirements-jupyter_devel.txt >> $tempfile + fi + + find $PROJECT_DIR/paperpi/plugins -type f -name "requirements-*.txt" -exec cat {} >> $tempfile \; + cat $tempfile + $VENV/bin/python -m pip install -r $tempfile + + echo "Activate the virtual environment by running: + $ source $PROJECT_DIR/utilities/venv_activate" + fi + + if [ $JUPYTER -gt 0 ] + then + echo "Installing kernel spec for $venvName" + if ! $VENV/bin/python -m pip show "ipykernel" > /dev/null; then + echo "Installying Jupyter ipykernel module for this virtual environment" + $VENV/bin/pip3 install ipykernel + fi + echo "Adding kernel spec: $venvName" + $VENV/bin/python -m ipykernel install --user --name "$venvName" + fi + + if [ $PURGE -gt 0 ] + then + echo "Purging kernelspec $venvName" + jupyter kernelspec remove $venvName $venvName + rm -rf $VENV + echo "Removing $VENV" + fi +} + +# give jupyter hints +function jupyter_hints { + if [ $JUPYTER -gt 0 ] + then + echo "Hints for staring a Jupyter session:" + MY_HOST=$(hostname -I | cut -d " " -f 1) + echo "To launch a Jupyter development environment, run: + $ jupyter notebook --ip=$MY_HOST --no-browser + + Then connect to http://$MY_HOST:8888 from a browser on the local network to get started" + fi +} + +function venv_info { + if [ ! -d $VENV ] + then + echo "No virtual environment exists for this project. +Create a virtual environment with: + $0 -c|-j + +For more information: + $0 -h + " + exit 0 + fi + + echo "Virtual environtment information + * Path: $VENV + * Activate virtual env: + $ source $PROJECT_DIR/utilities/venv_activate + +" + + if $VENV/bin/python3 -m pip show "ipykernel" > /dev/null; then + myHost=$(hostname -I | cut -d " " -f 1) + echo "Jupyter Information: + * Launch Jupyter Notebook locally: + $ cd ~; jupyter-notebook + + * Launch Jupyter Notebook for remote access: + $ cd ~; jupyter notebook --ip=$myHost --no-browser + +" + fi +} + +## main program ## +INSTALL=0 +PURGE=0 +JUPYTER=0 + +while [[ $# -gt 0 ]]; do + case $1 in + -h) + Help + exit + shift + shift + ;; + -c) + INSTALL=1 + PURGE=0 + shift + shift + ;; + -j) + INSTALL=1 + PURGE=0 + JUPYTER=1 + shift + shift + ;; + -p) + PURGE=1 + INSTALL=0 + shift + shift + ;; + + --info) + venv_info + exit 0 + ;; + -*) + echo "unknown option: $1" + echo "" + Help + exit + ;; + *) + shift + ;; + esac +done + +if [[ $INSTALL -eq 0 ]] && [[ $PURGE -eq 0 ]]; then + Help +fi + + +check_deb_system +check_spi +create_venv +jupyter_hints \ No newline at end of file diff --git a/utilities/install_waveshare_libs.sh b/utilities/install_waveshare_libs.sh new file mode 100755 index 0000000..678a41e --- /dev/null +++ b/utilities/install_waveshare_libs.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# update the waveshare libraries from github and patch some known issues + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +PROJECT_DIR=$(dirname $SCRIPT_DIR) + +# wavehsare repo +WS_REPO="https://github.com/waveshare/e-Paper.git" +WS_ROOT="e-Paper" +WS_LIB_PATH="RaspberryPi_JetsonNano/python/lib/waveshare_epd" + +WS_LOCAL="$PROJECT_DIR/paperpi/waveshare_epd" + +# git clone into temporary directory +# WS_TEMP=$(mktemp -d -t waveshare_XXXXX) + +WS_TEMP="/tmp/waveshare_Yr5PG" + +# git clone $WS_REPO $WS_TEMP +# if [[ $? -ne 0 ]]; +# then +# echo "failed to clone $WS_REPO" +# echo "see $WS_TEMP" +# exit 1 +# fi + +WS_VERSION=$(git --git-dir $WS_TEMP/.git log -1 --format=%h\ %ci) +echo "The current waveshare version is: $WS_VERSION" + +# copy the downloaded libraries into the project directory +cp -r $WS_TEMP/$WS_LIB_PATH $PROJECT_DIR/paperpi/ + +# # add the latest commit to the constants file for record keeping +sed -i "s#\(ws_version\s\?=\).*#\1 '$WS_VERSION'#g" $PROJECT_DIR/paperpi/my_constants.py + +echo "Patching issues with waveshare libraries" + +# ## Patch issues with WaveShare Modules ## +# # remove unneeded numpy imports in waveshare modules +# find $WS_LOCAL -type f -exec sed -i 's/^import numpy/#&/' {} \; + +# # add default value to `update` arg in init() method + echo " set update=false in init()" +find $WS_LOCAL -type f -exec sed -i -E 's/(^\W+def init\(self,\W+update)/\1=False/g' {} \; + +# # add default value to `color` arg in Clear() method (see epd2in7 for example) +# find $WS_LOCAL -type f -exec sed -i -E 's/(\W+def Clear\(self,\W+color)\)/\1=0xFF)/' {} \; + +# # default to full update in def init() for screens that support partial update +echo " set default lut value in init()" +find $WS_LOCAL -type f -exec sed -i -E 's/(def init\(self, lut)(.*)/\1=None\2\n if not lut:\n lut = self.lut_full_update/' {} \; + +# To resolve the issue below (wrong OS detected), replace a line in epdconfig.py +# https://github.com/waveshareteam/e-Paper/issues/306 +echo " patch wrong os detection in epdconfig.py" +sed -i "s|if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):|if os.path.exists('/etc/issue'):|" $WS_LOCAL/epdconfig.py \ No newline at end of file diff --git a/utilities/requirements-devel.txt b/utilities/requirements-devel.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/utilities/requirements-devel.txt @@ -0,0 +1 @@ + diff --git a/utilities/requirements-jupyter_devel.txt b/utilities/requirements-jupyter_devel.txt new file mode 100644 index 0000000..4f3a90e --- /dev/null +++ b/utilities/requirements-jupyter_devel.txt @@ -0,0 +1 @@ +jupytext