Compare commits

..

181 Commits

Author SHA1 Message Date
611a3e7fb5 fix for waveshare3in7.py 2024-02-15 20:51:55 +01:00
599c6211e4 version 2.8.4 2024-02-15 20:48:27 +01:00
eb48d29851 fix on 38 displays 2024-02-15 20:46:48 +01:00
0999b95be0 update build 2024-02-15 09:55:01 +01:00
ae351e5e9c update waveshare3in0g.py 2024-02-15 09:54:49 +01:00
fa58136c0e update waveshare3in7.py 2024-02-15 09:34:45 +01:00
3d5185f2c1 update waveshare3in7.py 2024-02-15 09:30:03 +01:00
b6bb7b9080 update waveshare3in7.py 2024-02-15 09:26:33 +01:00
20715351af revert back to drschottky 2024-02-14 08:53:54 +01:00
1d3c781d12 version 2.8.3 2024-02-13 23:25:55 +01:00
bd51b4330f version 2.8.3 2024-02-13 23:15:05 +01:00
f216a21132 update 2024-02-13 23:13:49 +01:00
5ae357c3dc Merge remote-tracking branch 'origin/master' 2024-02-13 23:11:10 +01:00
ed9afe6856 Revert "Changed from dphys-swapfile to zram-tools"
This reverts commit 26913016b9.
2024-02-13 23:10:53 +01:00
25d932fa9b Revert "zramswap"
This reverts commit 0dbd611ed5.
2024-02-13 23:10:52 +01:00
ebd25d50b0 Update README.md 2024-02-09 23:13:26 +01:00
27e784a5d7 update 2024-02-09 13:12:40 +01:00
c02efb5224 update Makefile 2024-02-09 13:11:02 +01:00
107d366c82 update Makefile 2024-02-08 21:40:28 +01:00
488968ba7f Revert "update Makefile"
This reverts commit 9a40567d
2024-02-08 20:18:58 +01:00
0dd8f72c95 Merge pull request #58 from jayofelony/dev
dev
2024-02-08 20:07:20 +01:00
0e274af5a0 Revert "Testing pcapng fileformat"
This reverts commit 7040be2d30.
2024-02-08 20:06:33 +01:00
8627c8800d Merge pull request #57 from jayofelony/dev
Dev
2024-02-08 07:53:53 +01:00
53ed6f61c6 Merge branch 'master' into dev
Signed-off-by: Jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-08 07:53:45 +01:00
835523241b update build 2024-02-08 07:51:19 +01:00
9a40567daa update Makefile 2024-02-06 22:12:05 +01:00
eab331686d Merge pull request #54 from crs-k/dev
Add PiShrink step to the workflow (#1)
2024-02-06 22:10:12 +01:00
e1d8001fb4 Add PiShrink step to the workflow (#1)
* Add PiShrink step to the workflow

* Add environment variables for Raspberry Pi 64-bit builder

* Update Makefile command to include debug information

* Add source distribution target to Makefile

* Remove unnecessary provisioner command

* Add armhf architecture support

* Remove armhf architecture provisioning

* Refactor Makefile to remove unnecessary files

* Update Makefile command in publish.yml

* Update pwngrid URL in raspberrypi64.yml

* Add permissions to publish workflow

* Remove unnecessary permissions in publish.yml
2024-02-06 12:53:45 -05:00
3cc172a526 update Makefile 2024-02-06 09:06:54 +01:00
41afe302d9 update Makefile 2024-02-06 09:05:42 +01:00
5bcca7e89b update README.md 2024-02-06 08:52:16 +01:00
4a12436942 add architecture armhf 2024-02-06 08:41:28 +01:00
d8b6363d37 Merge pull request #51
Waveshare 3.52 in e-ink update
2024-02-06 08:36:21 +01:00
b3d8a44208 Update waveshare3in52.py
Signed-off-by: Chris Kerins <clkerins@gmail.com>
2024-02-05 20:14:18 -05:00
ck
3fb91498cd Enable Makefile execution and remove disk image creation 2024-02-05 17:52:51 -05:00
ck
7587f38c28 Update disk.img path in publish.yml 2024-02-05 17:46:20 -05:00
ck
d7fefa78f0 Commented out make step and added code to create .img file 2024-02-05 17:40:38 -05:00
ck
1ef3a88679 Update distDir path in publish.yml 2024-02-05 17:34:23 -05:00
291ef39563 Update README.md to show support for Pi 5 2024-02-05 22:10:53 +01:00
16d80a09e6 Update README.md to show support for Pi 5 2024-02-05 22:10:34 +01:00
ck
4ffad03c91 Update distDir path in publish.yml 2024-02-05 15:44:50 -05:00
ck
0638832532 Update mountpoint for boot partition 2024-02-05 13:42:59 -05:00
ck
f895b06978 Update qemu binary paths for arm64 2024-02-05 13:19:56 -05:00
ck
f410feb2bb Add check for qemu-aarch64 in binfmt_misc 2024-02-05 13:09:36 -05:00
ck
1ffe6c4e3d Remove Makefile2 and update build process 2024-02-05 12:34:34 -05:00
ck
dfbfd7f891 Update pwngrid to version 1.11.1 2024-02-05 12:34:09 -05:00
ck
a50695aef2 Update publish workflow and add Makefile2 2024-02-05 12:18:04 -05:00
ck
829a6962d6 Update binfmt-support and add checks for qemu-user-static package, binfmt-support service, and binfmt_misc filesystem 2024-02-05 12:17:41 -05:00
ck
ce1315b85f Add binfmt_misc registration for qemu-aarch64 2024-02-05 12:08:07 -05:00
ck
6a2703cc27 Update QEMU in publish.yml 2024-02-05 11:34:03 -05:00
ck
502e856934 Update QEMU and restart binfmt-support 2024-02-05 11:22:39 -05:00
dffcbbf447 Revert "Revert "Testing pcapng fileformat""
This reverts commit d142840307.
2024-02-05 17:16:13 +01:00
ck
333804c3bb Remove unnecessary build configuration for Raspberry Pi 32 Pwnagotchi 2024-02-05 11:10:29 -05:00
ck
50b1ceed81 Remove unnecessary file from pwnagotchi build process 2024-02-05 11:01:49 -05:00
ck
877b9fbba3 Update Makefile and builder/pwnagotchi.json.pkr.hcl 2024-02-05 10:57:33 -05:00
ck
8724ca546d Update packer builder-arm source URL 2024-02-05 10:51:18 -05:00
961d3a536a Merge pull request #2 from crs-k/waveshare-352-support
Waveshare 352 support
2024-02-05 10:38:39 -05:00
ck
c882d0b67a Update arm plugin source in pwnagotchi.json.pkr.hcl 2024-02-05 10:29:01 -05:00
ck
12fd081ae0 Update required_plugins in pwnagotchi.json.pkr.hcl 2024-02-05 10:09:57 -05:00
ck
e1be0f7674 Remove unnecessary clean-up step in Makefile 2024-02-05 10:01:12 -05:00
396b30f780 Merge pull request #1 from crs-k:waveshare-352-support
Add publish workflow and update display layout
2024-02-05 09:31:24 -05:00
ck
e7d8d632a0 Add publish workflow and update display layout 2024-02-05 09:30:49 -05:00
5a6ec7b4b8 Next version will be 2.8.2 2024-02-04 18:28:09 +01:00
92cd5d3fdb Merge pull request #47 from jayofelony/dev
removed blind bug check from fix_services.py
2024-02-04 18:09:33 +01:00
99caa7a973 removed blind bug check from fix_services.py 2024-02-04 18:08:31 +01:00
a94e7eef02 Merge pull request #46 from jayofelony/dev
Dev to master
2024-02-04 18:04:44 +01:00
1cefae55d1 moved the majority of logging to debug 2024-02-04 17:48:22 +01:00
c5ee1df855 unused function 2024-02-04 17:44:05 +01:00
d142840307 Revert "Testing pcapng fileformat"
This reverts commit 7040be2d30.
2024-02-04 17:42:56 +01:00
e558146e28 moves the majority of logging to debug 2024-02-04 17:42:40 +01:00
11a3330153 small fix 2024-02-04 17:42:22 +01:00
53b2dd8628 update build for latest kernel 2024-02-04 17:42:10 +01:00
6381f9443b remove blind bug, as its not a blind bug anymore. 2024-02-04 17:41:57 +01:00
fa7e87b974 remove blind bug, as its not a blind bug anymore.
delayed hopping channels by .2 seconds to give firmware time to get ready for hopping.
2024-02-04 17:41:41 +01:00
cca2ff2da4 Merge pull request #45 from wpa-2/patch-1
MOTD updated
2024-02-03 17:09:03 +01:00
78415b3137 Update 01-motd
Maybe a good idea to point people to the new wiki instead. 


Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com>
2024-02-03 15:13:44 +00:00
34284aa1bc Change to seemoo-lab nexmon 2024-02-01 13:50:51 +01:00
56ebb60662 Change to seemoo-lab nexmon 2024-02-01 13:26:20 +01:00
84f6624844 Change to seemoo-lab nexmon 2024-02-01 13:04:06 +01:00
3bcbb0ce9a Version 2.8.1 2024-01-29 22:52:16 +01:00
e01e457992 Remove bettercap client settings, so you cannot mess it up. 2024-01-29 22:24:20 +01:00
1780859889 Merge pull request #37 from Ravioli5/patch-1
Update 01-motd
2024-01-29 16:15:12 +01:00
fdd98bb37a Update 01-motd
-fixed grammar (added a word)

Signed-off-by: Ravioli5 <157115073+Ravioli5@users.noreply.github.com>
2024-01-29 13:33:47 +05:30
86991304a5 Merge remote-tracking branch 'origin/dev' into dev 2024-01-28 22:12:20 +01:00
4f62759d6d Revert grid name 2024-01-28 22:12:06 +01:00
7b7ba02aad Changed setup.py 2024-01-28 22:12:06 +01:00
7040be2d30 Testing pcapng fileformat 2024-01-28 22:12:05 +01:00
d0617ccfaf Revert grid name 2024-01-28 22:08:17 +01:00
a0b5078b64 Changed setup.py 2024-01-28 22:05:14 +01:00
54c1ffd63c Updated wiglewifi version to 1.6 2024-01-28 22:02:57 +01:00
7530709d0c Updated wiglewifi version to 1.6 2024-01-28 21:46:50 +01:00
a9a6fd424b Small changes/fixes for debugging 2024-01-28 21:46:22 +01:00
8c97301992 Readability changes for webgpsmap.py 2024-01-28 21:45:53 +01:00
91eaa22188 Fix for waveshare2in13b_V4.py implementation 2024-01-28 21:44:19 +01:00
31a4af4c21 sudo pwnagotchi plugins update
`sudo pwnagotchi plugins list`

Do not work, somehow I forgot to remove a test I did.
2024-01-28 21:44:04 +01:00
dceeaff1fb Next update will be 2.8.0 2024-01-28 21:43:17 +01:00
c0241dc8df Update README.md 2024-01-27 16:11:59 +01:00
8f405f4ab2 Merge pull request #35 from Kal-Toh/patch-1
Update README.md
2024-01-27 16:11:19 +01:00
bd79e71563 Update README.md
This is a small change to address questions I had about the installation process.

Signed-off-by: Rory <104321806+Kal-Toh@users.noreply.github.com>
2024-01-27 14:03:40 +00:00
7f662585aa Merge pull request #34 from findingmoist/master
Update 01-motd
2024-01-27 10:03:24 +01:00
d23ff8d47a Update 01-motd
* Changed face so it shows
* updated python3 version so $_version shows the update number

Signed-off-by: findingmoist <128169791+findingmoist@users.noreply.github.com>
2024-01-26 18:56:40 -05:00
04435229fe Update build for RPi5 2024-01-26 15:28:04 +01:00
42e236bafe Update build for RPi5 2024-01-26 10:45:18 +01:00
5081b72695 Merge remote-tracking branch 'origin/master' 2024-01-25 23:48:49 +01:00
652740f050 Version 2.7.9
Add Esperanzo language
Updated Pt-Br language
Updated Italian language
2024-01-25 23:48:41 +01:00
1b6b12bdf5 Add Esperanzo language
Updated Pt-Br language
Updated Italian language
2024-01-25 23:48:06 +01:00
c610335a34 Add Esperanzo language
Edited Pt-Br language
2024-01-25 22:23:01 +01:00
6c39ed97dd Update build for Pi 5 users
Version 2.7.8
2024-01-25 21:38:04 +01:00
967f1663c6 Update build for Pi 5 users
Version 2.7.8
2024-01-25 17:51:15 +01:00
ffe1e90ccd Update build for Pi 5 users
Version 2.7.8
2024-01-25 17:49:17 +01:00
f2d2bcbfdf Update build for Pi 5 users
Version 2.7.8
2024-01-25 17:30:15 +01:00
bfc0795fb8 Update build for Pi 5 users
Version 2.7.8
2024-01-25 16:31:35 +01:00
1a55afd74a Update build for Pi 5 users
Version 2.7.8
2024-01-25 15:16:33 +01:00
1594e7c129 Update build for Pi 5 users
Version 2.7.8
2024-01-24 15:51:09 +01:00
a244e70a1c Update build for Pi 5 users
Version 2.7.8
2024-01-24 11:00:32 +01:00
d35d5d6c3c Update build for Pi 5 users
Version 2.7.8
2024-01-24 10:51:02 +01:00
7aacf9fb44 Update build for Pi 5 users
Version 2.7.8
2024-01-24 10:24:01 +01:00
dde6fa4c2a Update build for Pi 5 users 2024-01-24 01:47:23 +01:00
7dfb2f2ff6 Update build for Pi 5 users 2024-01-23 14:56:34 +01:00
cf46ab3da9 Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:47:06 +01:00
6824e541a4 Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:40:41 +01:00
1c4e8fa750 Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:36:46 +01:00
a50ec4a65c Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:35:12 +01:00
5414fdf21d Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 13:29:31 +01:00
c9883bb4f9 Add hcxtools to apt_packages.txt 2024-01-23 12:27:59 +01:00
045f5853bc Test 2024-01-23 12:26:33 +01:00
6dfcaf05d5 Hashie enabled by default 2024-01-23 12:26:00 +01:00
e2f8119d2c Install apt-packages while installing pwnagotchi, if needed 2024-01-23 12:22:30 +01:00
d675b3d0dd Added hcxtools as installed package. 2024-01-23 11:46:50 +01:00
30850b6530 Added hcxtools as installed package. 2024-01-23 11:42:47 +01:00
1e9c9bae42 Added hcxtools as installed package. 2024-01-23 11:38:14 +01:00
64241515ad Added hashie to default plugins, to convert pcaps to a crackable format from the start. 2024-01-23 11:37:34 +01:00
c9f232dae2 Added hashie to default plugins, to convert pcaps to a crackable format from the start. 2024-01-23 11:37:23 +01:00
4f97bcaa83 Moved aircrackonly to default plugins, is also enabled by default. To immediately delete empty handshakes. 2024-01-23 11:25:04 +01:00
7d2a03c79f Changing behaviour when mon_max_blind_epochs is hit, from full reboot to simple restart to save uptime. 2024-01-23 11:13:23 +01:00
f89ba85f73 Couple updated displays from Waveshare, not 213g.
166c012cde
2024-01-23 10:59:25 +01:00
57f03f4359 Removed paw-gps.py, as it is no longer supported. 2024-01-22 23:56:13 +01:00
9bc266f9ff Make wigle, wpa-sec, onlinehashcrack and grid plugins check against main.whitelist instead of their own whitelist. Possibly reduces possibility of errors in config.
https://github.com/jayofelony/pwnagotchi-bookworm/issues/24
2024-01-22 23:29:43 +01:00
b0db0285bc Version 2.7.7 2024-01-22 23:12:59 +01:00
cca3e77d50 Version 2.7.6 2024-01-22 14:25:16 +01:00
4fe603bf5e Small edit to net-pos.py 2024-01-22 12:35:21 +01:00
9a9ee70a78 Fixed wigle plugin 2024-01-22 12:06:20 +01:00
7fc8838f76 2.7.5 2024-01-21 11:43:58 +01:00
94b2ff7047 2.7.5 2024-01-21 11:40:27 +01:00
8edb0fdaa4 2.7.5 2024-01-21 11:33:22 +01:00
b557768159 Fix gdrivesync.py 2024-01-21 11:32:39 +01:00
5a6967eb4d Fix gdrivesync.py 2024-01-21 11:14:17 +01:00
c0c35231cf Fix gdrivesync.py 2024-01-21 11:13:51 +01:00
88362b3354 Version 2.7.4 2024-01-21 00:00:45 +01:00
e50cf04967 Moved self._display = None to base.py for easier debugging display files.
Fixed waveshare2in13g.py
2024-01-20 23:54:32 +01:00
85a64a3914 Merge pull request #23 from Opalinus/master
Repair broken Waveshare213g #22
2024-01-20 23:27:02 +01:00
63d0c20a3e Repair broken Waveshare213g 2024-01-20 20:16:01 +01:00
044639a6d4 Fix 2.7V2 display 2024-01-20 10:23:50 +01:00
7fc2c6b25f Update README.md 2024-01-19 12:25:08 +01:00
c5d5d9bb14 Changed Makefile 2024-01-19 09:04:08 +01:00
129ae92447 Version 2.7.3 2024-01-19 08:51:56 +01:00
2560692ee2 Fixed a mistake on display loading 2024-01-19 08:50:16 +01:00
1424e0d510 Added display waveshare2in66b 2024-01-19 08:43:00 +01:00
2c9eaa436a Added display waveshare2in13g 2024-01-19 08:34:41 +01:00
0c5c6058a5 Added display waveshare2in13g 2024-01-19 07:28:31 +01:00
a3fb39d78c Update README.md 2024-01-18 23:36:25 +01:00
bac62bc4aa Fix for pwnlib 2024-01-17 23:17:48 +01:00
f7a5f2a554 Update build 2024-01-17 21:55:27 +01:00
6921fd14a3 Update Makefile 2024-01-17 20:46:03 +01:00
0dbd611ed5 zramswap 2024-01-17 20:42:28 +01:00
18b9093f70 Version 2.7.2 2024-01-17 20:11:38 +01:00
26913016b9 Changed from dphys-swapfile to zram-tools
Fix on auto-update.py
2024-01-17 19:55:07 +01:00
0786b6757e Changed from dphys-swapfile to zram-tools
Fix on auto-update.py
2024-01-17 19:53:36 +01:00
0f4eda8039 Changed from ext4 to f2fs
Changed from dphys-swapfile to zram-tools
Fix on auto-update.py
2024-01-17 19:51:38 +01:00
1672a35f09 Changed MAC check for whitelist upto last 2 characters. 2024-01-17 18:28:53 +01:00
80e7e6c550 Changed MAC check for whitelist upto last 2 characters. 2024-01-17 18:26:45 +01:00
ca274036ab Version 2.7.1 2024-01-17 18:23:15 +01:00
649e8a4222 Small fixes 2024-01-17 18:22:57 +01:00
63f0a761c1 Added a skip for hostnames/mac addresses on whitelist 2024-01-17 18:22:42 +01:00
8a64918b55 Added Hebrew language 2024-01-16 10:45:47 +01:00
c27cc0ac24 Added 38 waveshare displays or so
Layouts may not be correct, but I have no way of testing that.
2024-01-15 22:46:18 +01:00
c9bdce0ea3 Add Pt-Br language 2024-01-15 20:45:37 +01:00
6422371346 Version 2.7.0 2024-01-15 14:55:26 +01:00
3c5a95e0b8 Version 2.7.0 2024-01-15 14:55:15 +01:00
18217119fc Version 2.6.9 2024-01-14 09:41:39 +01:00
b03b3119c7 Version 2.6.8 2024-01-13 19:03:25 +01:00
166 changed files with 3640 additions and 5313 deletions

1
.github/FUNDING.yml vendored
View File

@ -1,4 +1,3 @@
# These are supported funding model platforms
patreon: pwnagotchi_torch
github: jayofelony

212
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,212 @@
name: Publish
on:
workflow_dispatch:
inputs:
version:
description: 'Version number'
required: true
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Remove unnecessary directories
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/share/boost
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- name: Check disk space
run: df -BG
- name: Checkout code
uses: actions/checkout@v4
- name: Validate tag
id: tag-setter
run: |
TAG=${{ github.event.inputs.version }}
if [[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Tag $TAG is valid."
echo "TAG=$TAG" >> $GITHUB_OUTPUT
else
echo "Tag $TAG is not a valid semantic version. Aborting."
exit 1
fi
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.9
- name: Install dependencies
run: |
sudo apt-get update && sudo apt-get install -y libdbus-1-dev curl unzip gettext qemu-utils qemu qemu-user-static binfmt-support
pip install -r requirements.txt
- name: Update QEMU
run: |
sudo update-binfmts --enable qemu-aarch64
echo $(ls /usr/bin/qemu-aarch64-static)
- name: Restart binfmt-support
run: sudo service binfmt-support restart
- name: Mount binfmt_misc
run: |
if ! grep -qs '/proc/sys/fs/binfmt_misc ' /proc/mounts; then
echo "Mounting binfmt_misc"
sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
fi
- name: Restart binfmt-support
run: sudo service binfmt-support restart
- name: Update Languages
run: make update_langs
- name: Compile Languages
run: make compile_langs
- name: Check disk space
run: df -BG
- name: Check qemu-user-static package
run: |
echo "Checking qemu-user-static package..."
dpkg -s qemu-user-static && echo "qemu-user-static is installed." || echo "qemu-user-static is NOT installed."
- name: Check binfmt-support service
run: |
echo "Checking binfmt-support service..."
service binfmt-support status && echo "binfmt-support service is running." || echo "binfmt-support service is NOT running."
- name: Check binfmt_misc filesystem
run: |
echo "Checking binfmt_misc filesystem..."
mount | grep binfmt_misc && echo "binfmt_misc is mounted." || echo "binfmt_misc is NOT mounted."
echo $(ls /proc/sys/fs/binfmt_misc | grep qemu-aarch64)
- name: Run Makefile
run: make
env:
PWN_VERSION: ${{ steps.tag-setter.outputs.TAG }}
- name: PiShrink
run: |
wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
chmod +x pishrink.sh
sudo mv pishrink.sh /usr/local/bin
find /home/runner/work/ -type f -name "*.img" -exec sudo pishrink.sh {} \;
- name: Compress .img files
run: |
find /home/runner/work/ -type f -name "*.img" -exec xz --no-warn {} \;
- name: Create tag
uses: actions/github-script@v7
with:
script: |
const version = "${{ steps.tag-setter.outputs.TAG }}"
console.log(`Creating tag ${version}`)
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/tags/${version}`,
sha: context.sha
})
- name: Create Release
id: create_release
uses: actions/github-script@v7
with:
script: |
const tag = "${{ steps.tag-setter.outputs.TAG }}"
console.log(`Creating release with tag: ${tag}`)
const release = await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: tag,
name: tag,
draft: false,
prerelease: true,
generate_release_notes: true
})
console.log(`Created release with id: ${release.data.id}`)
return release.data.id
- name: Upload Release Asset
id: upload-release-asset
uses: actions/github-script@v7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
script: |
const fs = require('fs');
const path = require('path');
const release_id = "${{ steps.create_release.outputs.result }}";
const asset_content_type = 'application/octet-stream';
const distDir = '/home/runner/work/';
const uploadFile = async (filePath) => {
if (fs.lstatSync(filePath).isDirectory()) {
const files = fs.readdirSync(filePath);
for (const file of files) {
await uploadFile(path.join(filePath, file));
}
} else {
// Check if the file has a .xz extension
if (path.extname(filePath) === '.xz') {
console.log(`Uploading ${filePath}...`);
const asset_name = path.basename(filePath);
const asset_size = fs.statSync(filePath).size;
const asset = fs.createReadStream(filePath);
const response = await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release_id,
name: asset_name,
data: asset,
headers: {
'content-type': asset_content_type,
'content-length': asset_size
}
});
console.log(`Uploaded ${filePath}: ${response.data.browser_download_url}`);
}
}
}
await uploadFile(distDir);
- name: Update Release
uses: actions/github-script@v7
with:
script: |
const release_id = "${{ steps.create_release.outputs.result }}"
console.log(`Updating release with id: ${release_id}`)
github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release_id,
tag_name: "${{ steps.tag-setter.outputs.TAG }}",
name: "${{ steps.tag-setter.outputs.TAG }}",
draft: false,
prerelease: false
})
- name: Save environment variable
run: echo "${{ steps.tag-setter.outputs.TAG }}" > env_var.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: env-var
path: env_var.txt

21
.idea/deployment.xml generated
View File

@ -1,4 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" filePermissions="493" folderPermissions="493" remoteFilesAllowedToDisappearOnAutoupload="false" />
<component name="PublishConfigData" serverName="pwnagotchi" filePermissions="493" folderPermissions="493" remoteFilesAllowedToDisappearOnAutoupload="false" confirmBeforeUploading="false">
<option name="confirmBeforeUploading" value="false" />
<serverData>
<paths name="pwnagotchi">
<serverdata>
<mappings>
<mapping deploy="/usr/local/lib/python3.11/dist-packages/pwnagotchi" local="$PROJECT_DIR$/pwnagotchi" web="/" />
<mapping deploy="/usr/local/bin" local="$PROJECT_DIR$/bin" />
<mapping local="" />
</mappings>
<excludedPaths>
<excludedPath local="true" path="$PROJECT_DIR$/venv" />
<excludedPath local="true" path="$PROJECT_DIR$/pwnagotchi.egg-info" />
<excludedPath local="true" path="$PROJECT_DIR$/dist" />
<excludedPath local="true" path="$PROJECT_DIR$/builder/packer-builder-arm" />
</excludedPaths>
</serverdata>
</paths>
</serverData>
</component>
</project>

5
.idea/misc.xml generated
View File

@ -3,5 +3,8 @@
<component name="Black">
<option name="sdkName" value="Python 3.11 (pwnagotchi)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (pwnagotchi-torch-bookworm)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project>

2
.idea/pwnagotchi.iml generated
View File

@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (pwnagotchi-torch-bookworm)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">

View File

@ -1,4 +1,4 @@
PACKER_VERSION := 1.10.0
PACKER_VERSION := 1.10.1
PWN_HOSTNAME := pwnagotchi
PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py)
@ -64,5 +64,5 @@ pwnagotchi: $(SDIST) builder/pwnagotchi.json.pkr.hcl builder/raspberrypi64.yml $
image: pwnagotchi
clean:
- rm -rf build dist pwnagotchi.egg-info
- rm -f $(PACKER)
- rm -rf dist pwnagotchi.egg-info
- rm -f $(PACKER)

View File

@ -11,7 +11,7 @@ Select Credentials from the left menu, click Create Credentials, sel
Now, the product name and consent screen need to be set -> click Configure consent screen and follow the instructions. Once finished:
Select Application type to be Desktop application.
Select Application type to be Web application.
Enter an appropriate name.
@ -19,7 +19,7 @@ Input http://localhost/ for Authorized redirect URIs.
Select the correct oauth scope:
- drive
- drive.file
- drive.install
Click Create.

View File

@ -1,15 +1,19 @@
# Pwnagotchi-Torch
<a href="https://github.com/jayofelony/pwnagotchi-bookworm/releases/latest"><img alt="Release" src="https://img.shields.io/github/release/jayofelony/pwnagotchi-bookworm.svg"></a><br/>
**This fork of [Pwnagotchi](https://www.pwnagotchi.ai) is only for 64-bit Raspberry Pi's. Such as the 02W, 3(b+) and 4(b) ~~and the new Raspberry Pi 5~~!!.**
**This fork of [Pwnagotchi](https://www.pwnagotchi.ai) is only for 64-bit Raspberry Pi's. Such as the 02W, 3(b+) and 4(b) and the new Raspberry Pi 5!!.**
The RPi5 can only be used headless currently. (without display.)
It seems the Pi 5 is unable to run in monitor mode, will keep you updated on this.
If you are using an older 32-bit version Raspberry Pi, ZeroWH, use this [fork](https://github.com/jayofelony/pwnagotchi-torch/releases/tag/v2.6.4) and make sure you download the `armhf` version.
---
Download latest image file [here](https://github.com/jayofelony/pwnagotchi-bookworm/releases/tag/v2.6.2), and let it auto-update from here on out.
Download the latest image file [here](https://github.com/jayofelony/pwnagotchi-bookworm/releases/tag/v2.8.2), and let it auto-update from here on out.
**Use RPi imager to flash, please don't flash a new user as this will mess with logs created.**
- Select `Use Custom Image`
- Browse for the downloaded image file
- Select No under `Use OS Customization`
SSH credentials are `pi/raspberry`.

View File

@ -50,6 +50,7 @@ def pwnagotchi_cli():
agent.mode = 'auto'
agent.start()
config = agent.config()
while True:
try:
@ -59,6 +60,7 @@ def pwnagotchi_cli():
channels = agent.get_access_points_by_channel()
# for each channel
for ch, aps in channels:
time.sleep(0.2) # This is to make sure it doesn't error (https://github.com/seemoo-lab/nexmon/issues/596)
agent.set_channel(ch)
if not agent.is_stale() and agent.any_activity():
@ -66,6 +68,9 @@ def pwnagotchi_cli():
# for each ap on this channel
for ap in aps:
if ap['mac'][:13].lower in config['main']['whitelist'] or ap['hostname'] in config['main']['whitelist']:
logging.info(f"Found your MAC address {ap['mac']} - {config['main']['whitelist']}")
continue
# send an association frame in order to get for a PMKID
agent.associate(ap)
# deauth all client stations in order to get a full handshake
@ -157,7 +162,7 @@ def pwnagotchi_cli():
sys.exit(0)
if args.donate:
print("Donations can made @ https://www.patreon.com/pwnagotchi_torch \n\nBut only if you really want to!")
print("Donations can made @ https://github.com/sponsors/jayofelony \n\nBut only if you really want to!")
sys.exit(0)
if args.check_update:
@ -172,10 +177,14 @@ def pwnagotchi_cli():
% (pwnagotchi.__version__, latest_ver))
# input validation
if user_input.lower() in ('y', 'yes'):
os.system("rm /root/.auto-update && systemctl restart pwnagotchi")
if os.path.exists('/root/.auto-update'):
os.system("rm /root/.auto-update && systemctl restart pwnagotchi")
os.system("systemctl restart pwnagotchi")
print("Okay, give me a couple minutes. Just watch pwnlog while you wait.")
elif user_input.lower() in ('n', 'no'): # using this elif for readability
elif user_input.lower() in ('n', 'no'):
print("Okay, guess not!")
else:
print("Invalid input.")
else:
print("You are currently on the latest release, v%s." % pwnagotchi.__version__)
sys.exit(0)

View File

@ -5,4 +5,4 @@ iface usb0 inet static
network 10.0.0.0
broadcast 10.0.0.255
gateway 10.0.0.1
metric 101
metric 101

View File

@ -1,6 +1,6 @@
[Unit]
Description=pwnagotchi Deep Reinforcement Learning instrumenting bettercap for WiFI pwning.
Documentation=https://pwnagotchi.ai
Documentation=https://pwnagotchi.org
Wants=network.target
After=pwngrid-peer.service
@ -8,6 +8,7 @@ After=pwngrid-peer.service
Type=simple
WorkingDirectory=~
ExecStart=/usr/bin/pwnagotchi-launcher
ExecStopPost=/usr/bin/bash -c "if egrep -qi 'personality.clear_on_exit[ =]*true' /etc/pwnagotchi/config.toml ; then /usr/local/bin/pwnagotchi --clear; fi"
Restart=always
RestartSec=30
TasksMax=infinity

View File

@ -1,8 +1,8 @@
#!/bin/sh
_hostname=$(hostname)
_version=$(cut -d"'" -f2 < /usr/local/lib/python3.9/dist-packages/pwnagotchi/_version.py)
_version=$(cut -d"'" -f2 < /usr/local/lib/python3.11/dist-packages/pwnagotchi/_version.py)
echo
echo "(◕‿‿◕) $_hostname"
echo "(☉_☉ ) $_hostname"
echo
echo " Hi! I'm a pwnagotchi $_version, please take good care of me!"
echo " Here are some basic things you need to know to raise me properly!"
@ -30,4 +30,4 @@ echo
echo " You can restart me using"
echo " pwnkill"
echo
echo " You learn more about me at https://pwnagotchi.ai/"
echo " You can learn more about me at https://pwnagotchi.org/"

View File

@ -9,15 +9,6 @@ if is_crypted_mode; then
done
fi
# check if wifi driver is bugged
if ! check_brcm; then
if ! reload_brcm; then
echo "Could not reload wifi driver. Reboot"
reboot
fi
sleep 10
fi
# start mon0
start_monitor_interface

View File

@ -13,14 +13,6 @@ blink_led() {
sleep 0.3
}
# check if brcm is stuck
check_brcm() {
if [[ "$(journalctl -n10 -k --since -5m | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 5 ]]; then
return 1
fi
return 0
}
# reload mod
reload_brcm() {
if ! modprobe -r brcmfmac; then
@ -56,7 +48,7 @@ stop_monitor_interface() {
ifconfig wlan0 up
}
# returns 0 if the specificed network interface is up
# returns 0 if the specified network interface is up
is_interface_up() {
if grep -qi 'up' /sys/class/net/"$1"/operstate; then
return 0

View File

@ -1,11 +1,9 @@
# This is not working quite yet
# https://github.com/mkaczanowski/packer-builder-arm/pull/172
packer {
required_plugins {
#arm = {
# version = "~> 1"
# source = "github.com/cdecoux/builder-arm"
#}
arm = {
version = "1.0.0"
source = "github.com/cdecoux/builder-arm"
}
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
@ -28,8 +26,8 @@ source "arm" "rpi64-pwnagotchi" {
file_target_extension = "xz"
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
image_path = "../../../pwnagotchi-rpi-bookworm-${var.pwn_version}-arm64.img"
qemu_binary_source_path = "/usr/bin/qemu-aarch64-static"
qemu_binary_destination_path = "/usr/bin/qemu-aarch64-static"
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
image_build_method = "resize"
image_size = "9G"
image_type = "dos"
@ -51,6 +49,8 @@ source "arm" "rpi64-pwnagotchi" {
}
}
# a build block invokes sources and runs provisioning steps on them. The
# documentation for build blocks can be found here:
# https://www.packer.io/docs/from-1.5/blocks/build
@ -82,7 +82,6 @@ build {
"data/etc/systemd/system/pwngrid-peer.service",
]
}
provisioner "file" {
destination = "/etc/update-motd.d/01-motd"
source = "data/etc/update-motd.d/01-motd"

View File

@ -6,7 +6,8 @@
vars:
kernel:
min: "6.1"
full: "6.1.0-rpi7-rpi-v8"
full: "6.1.0-rpi8-rpi-v8"
full_pi5: "6.1.0-rpi8-rpi-2712"
pwnagotchi:
hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}"
version: "{{ lookup('env', 'PWN_VERSION') | default('pwnagotchi-torch', true) }}"
@ -23,7 +24,6 @@
services:
enable:
- bettercap.service
- dphys-swapfile.service
- fstrim.timer
- pwnagotchi.service
- pwngrid-peer.service
@ -32,18 +32,14 @@
- apt-daily-upgrade.timer
- apt-daily.service
- apt-daily.timer
- avahi-daemon.service
- avahi-daemon.socket
- bluetooth.service
- ifup@wlan0.service
- triggerhappy.service
- wpa_supplicant.service
packages:
caplets:
source: "https://github.com/jayofelony/caplets.git"
bettercap:
source: "https://github.com/jayofelony/bettercap.git"
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.2/bettercap-2.32.2.zip"
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.4/bettercap-2.32.4.zip"
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
pwngrid:
source: "https://github.com/jayofelony/pwngrid.git"
@ -55,12 +51,20 @@
- libpcap0.8-dev_1.9.1-4_arm64.deb
- libpcap0.8_1.9.1-4_arm64.deb
hold:
- firmware-atheros
- firmware-brcm80211
- firmware-libertas
- firmware-misc-nonfree
- firmware-realtek
- libpcap-dev
- libpcap0.8
- libpcap0.8-dev
- libpcap0.8-dbg
- libpcap0.8-dev
remove:
- avahi-daemon
- dhpys-swapfile
- libcurl-ocaml-dev
- libssl-ocaml-dev
- nfs-common
- triggerhappy
- wpasupplicant
@ -75,6 +79,11 @@
- dkms
- dphys-swapfile
- fbi
- firmware-atheros
- firmware-brcm80211
- firmware-libertas
- firmware-misc-nonfree
- firmware-realtek
- flex
- fonts-dejavu
- fonts-dejavu-core
@ -84,6 +93,7 @@
- gawk
- gcc-arm-none-eabi
- git
- hcxtools
- libatlas-base-dev
- libavcodec59
- libavformat59
@ -93,6 +103,7 @@
- libc-ares-dev
- libc6-dev
- libcap-dev
- libcurl-ocaml-dev
- libdbus-1-dev
- libdbus-glib-1-dev
- libeigen3-dev
@ -119,34 +130,30 @@
- libraspberrypi0
- libsqlite3-dev
- libssl-dev
- libssl-ocaml-dev
- libswscale5
- libtiff6
- libtool
- libusb-1.0-0-dev
- lsof
- make
- python3-yaml
- python3-dbus
- python3-flask
- python3-flask-cors
- python3-flaskext.wtf
- python3-gast
- python3-pil
- python3-pip
- python3-pycryptodome
- python3-requests
- python3-scapy
- python3-setuptools
- python3-smbus
- python3-smbus2
- python3-spidev
- python3-tweepy
- python3-werkzeug
- firmware-atheros
- firmware-brcm80211
- firmware-libertas
- firmware-misc-nonfree
- firmware-realtek
- python3-pip
- python3-setuptools
- python3-smbus
- python3-yaml
- qpdf
- raspberrypi-kernel-headers
- rsync
@ -163,15 +170,51 @@
- zlib1g-dev
environment:
ARCHFLAGS: "-arch aarch64"
QEMU_UNAME: "{{ kernel.full }}"
tasks:
# First we install packages
- name: install packages
apt:
name: "{{ packages.apt.install }}"
state: present
update_cache: yes
install_recommends: false
# Now we set up /boot/firmware
- name: Create pi user
copy:
dest: /boot/firmware/userconf
content: |
pi:$6$3jNr0GA9KIyt4hmM$efeVIopdMQ8DGgEPCWWlbx3mJJNAYci1lEXGdlky0xPyjqwKNbwTL5SrCcpb4144C4IvzWjn7Iv.QjqmU7iyT/
- name: enable ssh on boot
file:
path: /boot/firmware/ssh
state: touch
- name: adjust /boot/firmware/config.txt
lineinfile:
dest: /boot/firmware/config.txt
insertafter: EOF
line: '{{ item }}'
with_items: "{{ system.boot_options }}"
- name: change root partition
replace:
dest: /boot/firmware/cmdline.txt
backup: no
regexp: "root=PARTUUID=[a-zA-Z0-9\\-]+"
replace: "root=/dev/mmcblk0p2"
- name: configure /boot/firmware/cmdline.txt
lineinfile:
path: /boot/firmware/cmdline.txt
backrefs: True
state: present
backup: no
regexp: '(.*)$'
line: '\1 modules-load=dwc2,g_ether'
- name: change hostname
lineinfile:
dest: /etc/hostname
@ -189,6 +232,7 @@
state: present
when: hostname.changed
# Now we disable sap and a2dp, we don't use them on rpi
- name: disable sap plugin for bluetooth.service
lineinfile:
dest: /lib/systemd/system/bluetooth.service
@ -196,19 +240,6 @@
line: 'ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp'
state: present
- name: configure dphys-swapfile
lineinfile:
path: /etc/dphys-swapfile
regexp: "^CONF_SWAPSIZE=.*$"
line: "CONF_SWAPSIZE=2048"
- name: install packages
apt:
name: "{{ packages.apt.install }}"
state: present
update_cache: yes
install_recommends: false
###########################################
#
# libpcap v1.9 - build from source
@ -242,35 +273,116 @@
dest: /usr/local/lib/libpcap.so.0.8
state: link
# Install nexmon to fix wireless scanning (takes 2.5G of space)
# install latest hcxtools
- name: clone hcxtools
git:
repo: https://github.com/ZerBea/hcxtools.git
dest: /usr/local/src/hcxtools
- name: install hcxtools
shell: "make && make install"
args:
executable: /bin/bash
chdir: /usr/local/src/hcxtools
- name: remove hcxtools directory
file:
state: absent
path: /usr/local/src/hcxtools
- name: clone nexmon repository
git:
repo: https://github.com/DrSchottky/nexmon.git
dest: /usr/local/src/nexmon
- name: make firmware
# FIRST WE BUILD DRIVER FOR RPi5
- name: make firmware, RPi5
shell: "source ./setup_env.sh && make"
args:
executable: /bin/bash
chdir: /usr/local/src/nexmon/
environment:
QEMU_UNAME: "{{ kernel.full_pi5 }}"
ARCHFLAGS: "-arch aarch64"
- name: make firmware patch (bcm43455c0)
- name: make firmware patch (bcm43455c0), RPi5
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make"
args:
executable: /bin/bash
chdir: /usr/local/src/nexmon/
environment:
QEMU_UNAME: "{{ kernel.full_pi5 }}"
ARCHFLAGS: "-arch aarch64"
- name: install new firmware (bcm43455c0)
- name: copy modified driver, RPi5
copy:
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
dest: "/usr/lib/modules/{{ kernel.full_pi5 }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
environment:
QEMU_UNAME: "{{ kernel.full_pi5 }}"
ARCHFLAGS: "-arch aarch64"
- name: Delete the modified driver, RPi5
file:
state: absent
path: '/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko'
- name: backup original driver, RPi5
command: "mv /usr/lib/modules/{{ kernel.full_pi5 }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz /usr/lib/modules/{{ kernel.full_pi5 }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig"
- name: load brcmfmac drivers
command: "/sbin/depmod {{ kernel.full_pi5 }}"
environment:
QEMU_UNAME: "{{ kernel.full_pi5 }}"
- name: Delete nexmon content & directory
file:
state: absent
path: /usr/local/src/nexmon/
# NOW WE BUILD DRIVERS FOR RPi4, RPizero2w and RPi3
- name: clone nexmon repository
git:
repo: https://github.com/DrSchottky/nexmon.git
dest: /usr/local/src/nexmon
- name: make firmware, RPi4
shell: "source ./setup_env.sh && make"
args:
executable: /bin/bash
chdir: /usr/local/src/nexmon/
environment:
QEMU_UNAME: "{{ kernel.full }}"
ARCHFLAGS: "-arch aarch64"
- name: make firmware patch (bcm43455c0), RPi4
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make"
args:
executable: /bin/bash
chdir: /usr/local/src/nexmon/
environment:
QEMU_UNAME: "{{ kernel.full }}"
ARCHFLAGS: "-arch aarch64"
- name: install new firmware (bcm43455c0), RPi4 RPi5
copy:
src: /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/brcmfmac43455-sdio.bin
dest: /usr/lib/firmware/brcm/brcmfmac43455-sdio.bin
follow: true
# NOW WE BUILD DRIVERS FOR RPiZero2W, RPi 3
- name: make firmware patch (bcm43436b0)
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make"
args:
executable: /bin/bash
chdir: /usr/local/src/nexmon/
environment:
QEMU_UNAME: "{{ kernel.full }}"
ARCHFLAGS: "-arch aarch64"
- name: install new firmware (bcm43436b0)
copy:
@ -283,6 +395,17 @@
args:
executable: /bin/bash
chdir: /usr/local/src/nexmon/
environment:
QEMU_UNAME: "{{ kernel.full }}"
ARCHFLAGS: "-arch aarch64"
- name: copy modified driver, RPi4
copy:
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
dest: "/usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
environment:
QEMU_UNAME: "{{ kernel.full }}"
ARCHFLAGS: "-arch aarch64"
- name: install new firmware (bcm43430a1)
copy:
@ -313,13 +436,10 @@
- name: backup original driver
command: "mv /usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz /usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig"
- name: copy modified driver
copy:
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
dest: "/usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
- name : load brcmfmac drivers
command: "/sbin/depmod -a"
- name: load brcmfmac drivers
command: "/sbin/depmod {{ kernel.full }}"
environment:
QEMU_UNAME: "{{ kernel.full }}"
# To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation
- name: Delete nexmon content & directory
@ -394,7 +514,7 @@
repo: "{{ packages.bettercap.source }}"
dest: /usr/local/src/bettercap
- name: install bettercap 2.32.2
- name: install bettercap 2.32.4
shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && go mod tidy && make && make install"
args:
executable: /bin/bash
@ -477,41 +597,6 @@
state: absent
path: /etc/update-motd.d/10-uname
- name: enable ssh on boot
file:
path: /boot/firmware/ssh
state: touch
- name: adjust /boot/config.txt
lineinfile:
dest: /boot/firmware/config.txt
insertafter: EOF
line: '{{ item }}'
with_items: "{{ system.boot_options }}"
- name: adjust /etc/modules
lineinfile:
dest: /etc/modules
insertafter: EOF
line: '{{ item }}'
with_items: "{{ system.modules }}"
- name: change root partition
replace:
dest: /boot/firmware/cmdline.txt
backup: no
regexp: "root=PARTUUID=[a-zA-Z0-9\\-]+"
replace: "root=/dev/mmcblk0p2"
- name: configure /boot/cmdline.txt
lineinfile:
path: /boot/cmdline.txt
backrefs: True
state: present
backup: no
regexp: '(.*)$'
line: '\1 modules-load=dwc2,g_ether'
- name: Add pwnlog alias
lineinfile:
dest: /home/pi/.bashrc
@ -563,18 +648,6 @@
group: pi
recurse: true
- name: remove unnecessary apt packages
apt:
name: "{{ packages.apt.remove }}"
state: absent
purge: yes
register: removed
- name: clean apt cache
apt:
autoclean: true
when: removed.changed
- name: remove pre-collected packages zip
file:
path: /root/go_pkgs.tgz
@ -595,11 +668,6 @@
state: absent
path: /root/.cache/pip
- name: remove dependencies that are no longer required
apt:
autoremove: yes
when: removed.changed
- name: remove ssh keys
file:
state: absent
@ -612,6 +680,24 @@
args:
executable: /bin/bash
# Now we remove packages
- name: remove unnecessary apt packages
apt:
name: "{{ packages.apt.remove }}"
state: absent
purge: yes
register: removed
- name: remove dependencies that are no longer required
apt:
autoremove: yes
when: removed.changed
- name: clean apt cache
apt:
autoclean: true
when: removed.changed
handlers:
- name: reload systemd services
systemd:

View File

@ -1 +1 @@
__version__ = '2.6.7'
__version__ = '2.8.4'

View File

@ -21,17 +21,17 @@ RECOVERY_DATA_FILE = '/root/.pwnagotchi-recovery'
class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
def __init__(self, view, config, keypair):
Client.__init__(self, config['bettercap']['hostname'],
config['bettercap']['scheme'],
config['bettercap']['port'],
config['bettercap']['username'],
config['bettercap']['password'])
Client.__init__(self,
"127.0.0.1" if "hostname" not in config['bettercap'] else config['bettercap']['hostname'],
"http" if "scheme" not in config['bettercap'] else config['bettercap']['scheme'],
8081 if "port" not in config['bettercap'] else config['bettercap']['port'],
"pwnagotchi" if "username" not in config['bettercap'] else config['bettercap']['username'],
"pwnagotchi" if "password" not in config['bettercap'] else config['bettercap']['password'])
Automata.__init__(self, config, view)
AsyncAdvertiser.__init__(self, config, view, keypair)
AsyncTrainer.__init__(self, config)
self._started_at = time.time()
self._filter = None if not config['main']['filter'] else re.compile(config['main']['filter'])
self._current_channel = 0
self._tot_aps = 0
self._aps_on_channel = 0
@ -164,11 +164,6 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
self.wait_for(recon_time, sleeping=False)
def _filter_included(self, ap):
return self._filter is None or \
self._filter.match(ap['hostname']) is not None or \
self._filter.match(ap['mac']) is not None
def set_access_points(self, aps):
self._access_points = aps
plugins.on('wifi_update', self, aps)
@ -184,13 +179,12 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
for ap in s['wifi']['aps']:
if ap['encryption'] == '' or ap['encryption'] == 'OPEN':
continue
elif ap['hostname'] not in whitelist \
and ap['mac'].lower() not in whitelist \
and ap['mac'][:8].lower() not in whitelist:
if self._filter_included(ap):
aps.append(ap)
elif ap['hostname'] in whitelist or ap['mac'][:13].lower() in whitelist or ap['mac'].lower() in whitelist:
continue
else:
aps.append(ap)
except Exception as e:
logging.exception("Error while getting acces points (%s)", e)
logging.exception("Error while getting access points (%s)", e)
aps.sort(key=lambda ap: ap['channel'])
return self.set_access_points(aps)
@ -275,6 +269,10 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
self._save_recovery_data()
pwnagotchi.reboot()
def _restart(self):
self._save_recovery_data()
pwnagotchi.restart("AUTO")
def _save_recovery_data(self):
logging.warning("writing recovery data to %s ...", RECOVERY_DATA_FILE)
with open(RECOVERY_DATA_FILE, 'w') as fp:
@ -427,7 +425,6 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
if self.is_stale():
logging.debug("recon is stale, skipping assoc(%s)", ap['mac'])
return
if throttle == -1 and "throttle_a" in self._config['personality']:
throttle = self._config['personality']['throttle_a']

View File

@ -59,7 +59,8 @@ def load(config, agent, epoch, from_disk=True):
return a2c
except Exception as e:
logging.exception("[AI] error while starting AI (%s)", e)
logging.info("[AI] Error while starting AI")
logging.debug("[AI] error while starting AI (%s)", e)
logging.info("[AI] Deleting brain and restarting.")
os.system("rm /root/brain.nn && service pwnagotchi restart")

View File

@ -138,6 +138,6 @@ class Automata(object):
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
logging.critical("%d epochs without visible access points -> rebooting ...", self._epoch.blind_for)
self._reboot()
logging.critical("%d epochs without visible access points -> restarting ...", self._epoch.blind_for)
self._restart()
self._epoch.blind_for = 0

View File

@ -1,5 +1,11 @@
main.name = "pwnagotchi"
main.lang = "en"
main.whitelist = [
"EXAMPLE_NETWORK",
"ANOTHER_EXAMPLE_NETWORK",
"fo:od:ba:be:fo:od",
"fo:od:ba"
]
main.confd = "/etc/pwnagotchi/conf.d/"
main.custom_plugin_repos = [
"https://github.com/jayofelony/pwnagotchi-torch-plugins/archive/master.zip",
@ -12,6 +18,10 @@ main.custom_plugin_repos = [
main.custom_plugins = "/usr/local/share/pwnagotchi/custom-plugins/"
main.plugins.aircrackonly.enabled = true
main.plugins.hashie.enabled = true
main.plugins.auto-update.enabled = true
main.plugins.auto-update.install = true
main.plugins.auto-update.interval = 1
@ -55,9 +65,6 @@ main.plugins.gps.device = "/dev/ttyUSB0" # for GPSD: "localhost:2947"
main.plugins.grid.enabled = true
main.plugins.grid.report = true
main.plugins.grid.exclude = [
"YourHomeNetworkHere"
]
main.plugins.logtail.enabled = false
main.plugins.logtail.max-lines = 10000
@ -73,10 +80,6 @@ main.plugins.onlinehashcrack.enabled = false
main.plugins.onlinehashcrack.email = ""
main.plugins.onlinehashcrack.dashboard = ""
main.plugins.onlinehashcrack.single_files = false
main.plugins.onlinehashcrack.whitelist = []
main.plugins.paw-gps.enabled = false
main.plugins.paw-gps.ip = "192.168.44.1:8080"
main.plugins.pisugar2.enabled = false
main.plugins.pisugar2.shutdown = 5
@ -100,26 +103,19 @@ main.plugins.webgpsmap.enabled = false
main.plugins.wigle.enabled = false
main.plugins.wigle.api_key = ""
main.plugins.wigle.whitelist = []
main.plugins.wigle.donate = true
main.plugins.wigle.donate = false
main.plugins.wpa-sec.enabled = false
main.plugins.wpa-sec.api_key = ""
main.plugins.wpa-sec.api_url = "https://wpa-sec.stanev.org"
main.plugins.wpa-sec.download_results = false
main.plugins.wpa-sec.whitelist = []
main.iface = "wlan0mon"
main.mon_start_cmd = "/usr/bin/monstart"
main.mon_stop_cmd = "/usr/bin/monstop"
main.mon_max_blind_epochs = 50
main.no_restart = false
main.whitelist = [
"EXAMPLE_NETWORK",
"ANOTHER_EXAMPLE_NETWORK",
"fo:od:ba:be:fo:od",
"fo:od:ba"
]
main.filter = ""
main.log.path = "/home/pi/logs/pwnagotchi.log"
@ -160,6 +156,8 @@ personality.bond_encounters_factor = 20000
personality.throttle_a = 0.4
personality.throttle_d = 0.9
personality.clear_on_exit = true # clear display when shutting down cleanly
ui.fps = 0.0
ui.font.name = "DejaVuSansMono" # for japanese: fonts-japanese-gothic
ui.font.size_offset = 0 # will be added to the font size
@ -202,11 +200,6 @@ ui.display.enabled = false
ui.display.rotation = 180
ui.display.type = "waveshare_4"
bettercap.scheme = "http"
bettercap.hostname = "localhost"
bettercap.port = 8081
bettercap.username = "pwnagotchi"
bettercap.password = "pwnagotchi"
bettercap.handshakes = "/root/handshakes"
bettercap.silence = [
"ble.device.new",

View File

@ -1,14 +1,13 @@
# SOME DESCRIPTIVE TITLE.
# Pwnagotchi display English to Esperanto.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# FIRST AUTHOR MADE THIS IN YEAR 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-16 21:10+0100\n"
"POT-Creation-Date: 2024-01-25 23:40+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,218 +17,219 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr ""
msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr ""
msgstr "Sal, mi estas Pwnagotchi! Komencante…"
msgid "New day, new hunt, new pwns!"
msgstr ""
msgstr "Nova tago, nova ĉaso, nova wifi!"
msgid "Hack the Planet!"
msgstr ""
msgstr "Eniru la elektronikon!"
msgid "AI ready."
msgstr ""
msgstr "Mi pretas."
msgid "The neural network is ready."
msgstr ""
msgstr "La elektronika reto estas preta."
msgid "Generating keys, do not turn off ..."
msgstr ""
msgstr "Mi generas ŝlosilojn, ne malŝaltu min!"
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr ""
msgstr "Hej, kanalo {channel} disponeblas! Via alirpunkto dankos vin"
msgid "Reading last session logs ..."
msgstr ""
msgstr "Legante protokolojn de antaŭa sesio…"
#, python-brace-format
msgid "Read {lines_so_far} log lines so far ..."
msgstr ""
msgstr "legi {lines_so_far} liniojn ĝis nun…"
msgid "I'm bored ..."
msgstr ""
msgstr "Mi enuas…"
msgid "Let's go for a walk!"
msgstr ""
msgstr "Ni iru promeni!"
msgid "This is the best day of my life!"
msgstr ""
msgstr "Plej bona tago de mia vivo!"
msgid "Shitty day :/"
msgstr ""
msgstr "Terura tago :/"
msgid "I'm extremely bored ..."
msgstr ""
msgstr "mi estas tre enuigita…"
msgid "I'm very sad ..."
msgstr ""
msgstr "Mi estas tre malĝoja…"
msgid "I'm sad"
msgstr ""
msgstr "Mi estas malfeliĉa"
msgid "Leave me alone ..."
msgstr ""
msgstr "Lasu min sola…"
msgid "I'm mad at you!"
msgstr ""
msgstr "Mi koleras kontraŭ vi!"
msgid "I'm living the life!"
msgstr ""
msgstr "Mi ĝuas la vivon!"
msgid "I pwn therefore I am."
msgstr ""
msgstr "Mi eniras tial mi estas."
msgid "So many networks!!!"
msgstr ""
msgstr "Tiom da ludiloj!"
msgid "I'm having so much fun!"
msgstr ""
msgstr "Mi tre amuzas!"
msgid "My crime is that of curiosity ..."
msgstr ""
msgstr "Scivolemo estas mia krimo…"
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr ""
msgstr "Sal {name}! Mi ĝojas renkonti vin."
#, python-brace-format
msgid "Yo {name}! Sup?"
msgstr ""
msgstr "Hej {name}! Sal?"
#, python-brace-format
msgid "Hey {name} how are you doing?"
msgstr ""
msgstr "Sal {name}! Kiel vi fartas?"
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr ""
msgstr "Iu estas proksime! Ĝia nomo estas {name}."
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr ""
msgstr "Adiaŭ {name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr ""
msgstr "{name} malaperis…"
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr ""
msgstr "Hups… {name} malaperis…"
#, python-brace-format
msgid "{name} missed!"
msgstr ""
msgstr "{name} mankis!"
msgid "Missed!"
msgstr ""
msgstr "Maltrafis!"
msgid "Good friends are a blessing!"
msgstr ""
msgstr "Bonaj amikoj estas beno!"
msgid "I love my friends!"
msgstr ""
msgstr "Mi amas miajn amikojn!"
msgid "Nobody wants to play with me ..."
msgstr ""
msgstr "Neniu volas ludi kun mi..."
msgid "I feel so alone ..."
msgstr ""
msgstr "Mi estas tiel sola..."
msgid "Where's everybody?!"
msgstr ""
msgstr "KIE ĈIUJ ESTAS?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr ""
msgstr "Dormeto por {sec}j…"
msgid "Zzzzz"
msgstr ""
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
msgstr "ZzzZzzz ({sec}j)"
msgid "Good night."
msgstr ""
msgstr "Bonan nokton"
msgid "Zzz"
msgstr ""
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr ""
msgstr "Atendas {sec}j…"
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr ""
msgstr "Ĉirkaŭrigardante ({sec}j)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr ""
msgstr "Hej {what}, ni estu amikoj!"
#, python-brace-format
msgid "Associating to {what}"
msgstr ""
msgstr "asociante al {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr ""
msgstr "Hej {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr ""
msgstr "Ĵus decidis, ke {mac} ne bezonas konekton!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr ""
msgstr "Malaŭtentigi {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr ""
msgstr "Forigante {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr ""
msgstr "Mirinda, ni havas {num} novajn manpremojn!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr ""
msgstr "Vi nun havas {num} novajn mesaĝojn"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr ""
msgstr "Lo okazis... Rekomencante…"
#, python-brace-format
msgid "Uploading data to {to} ..."
msgstr ""
msgstr "alŝuti datumojn al {to}…"
#, python-brace-format
msgid "Downloading from {name} ..."
msgstr ""
msgstr "Elŝutu de {name}…"
#, python-brace-format
#, fuzzy, python-brace-format
msgid "Kicked {num} stations\n"
msgstr ""
msgstr "Forigita de {num} stacioj"
#, fuzzy
msgid "Made >999 new friends\n"
msgstr ""
msgstr "Faris pli ol 999 novajn amikojn!"
#, python-brace-format
#, fuzzy, python-brace-format
msgid "Made {num} new friends\n"
msgstr ""
msgstr "faris (nombro) novajn amikojn"
#, python-brace-format
#, fuzzy, python-brace-format
msgid "Got {num} handshakes\n"
msgstr ""
msgstr "Ricevis {num} novajn manpremojn"
msgid "Met 1 peer"
msgstr ""
msgstr "Renkontita unu kolego"
#, python-brace-format
msgid "Met {num} peers"
msgstr ""
msgstr "renkontitajn {num} kolegojn"
#, python-brace-format
msgid ""
@ -237,21 +237,24 @@ msgid ""
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
"Mi pwning dum {duration} kaj piedbatis {deauthed} klientojn!Mi ankaŭ "
"renkontis {associated} novajn amikojn kaj manĝis {handshakes} manpremojn!"
"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr ""
msgstr "horror"
msgid "minutes"
msgstr ""
msgstr "minutoj"
msgid "seconds"
msgstr ""
msgstr "sekundoj"
msgid "hour"
msgstr ""
msgstr "horo"
msgid "minute"
msgstr ""
msgstr "minuto"
msgid "second"
msgstr ""
msgstr "dua"

View File

@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-16 21:51+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Last-Translator: neo0oen \n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: Hebrew\n"
"MIME-Version: 1.0\n"
@ -18,240 +18,242 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr ""
msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr ""
msgstr "שלום, אני פוונגוטצ'י! מתחיל . . ."
msgid "New day, new hunt, new pwns!"
msgstr ""
msgstr "יום חדש, ציד חדש, ניצחונות חדשים !"
msgid "Hack the Planet!"
msgstr ""
msgstr "פרוץ לכדור הארץ !"
msgid "AI ready."
msgstr ""
msgstr "הבינה המלאחות'ית מוכנה"
msgid "The neural network is ready."
msgstr ""
msgstr "הרשת הניורולוגית העצבית מוכנה."
msgid "Generating keys, do not turn off ..."
msgstr ""
msgstr "יוצר מפתחות, בבקשה אל תכבה אותי"
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr ""
msgstr "היי , הערוץ {channel}פנוי ,נקודת הגישה שלך אומרת תודה "
msgid "Reading last session logs ..."
msgstr ""
msgstr ". . . קורא לוגים מאז ההפעלה האחרונה"
#, python-brace-format
msgid "Read {lines_so_far} log lines so far ..."
msgstr ""
msgstr "קראתי {lines_so_far} שורות מהלוג עד עכשיו . . ."
msgid "I'm bored ..."
msgstr ""
msgstr "אני משועמם . . ."
msgid "Let's go for a walk!"
msgstr ""
msgstr "בוא ניצא לטיול! "
msgid "This is the best day of my life!"
msgstr ""
msgstr "זה היום הכי טוב בחיי!"
msgid "Shitty day :/"
msgstr ""
msgstr "יום מחורבן :/"
msgid "I'm extremely bored ..."
msgstr ""
msgstr "אני משועמם בטירוף . . ."
msgid "I'm very sad ..."
msgstr ""
msgstr "אני עצוב נורא . . ."
msgid "I'm sad"
msgstr ""
msgstr "אני עצוב"
msgid "Leave me alone ..."
msgstr ""
msgstr "עזוב אותי בשקט . . ."
msgid "I'm mad at you!"
msgstr ""
msgstr "אני כועס עלייך!"
msgid "I'm living the life!"
msgstr ""
msgstr "אני חי את החיים!"
msgid "I pwn therefore I am."
msgstr ""
msgstr "אני שולט לכן אני כאן."
msgid "So many networks!!!"
msgstr ""
msgstr "כל כך הרבה רשתות! ! !"
msgid "I'm having so much fun!"
msgstr ""
msgstr "אני כל כך נהנה ועושה הרבה כיף!"
msgid "My crime is that of curiosity ..."
msgstr ""
msgstr "הפשע שלי הוא הסקרנות . . ."
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr ""
msgstr "שלום {name}! נעים להכיר אותך."
#, python-brace-format
msgid "Yo {name}! Sup?"
msgstr ""
msgstr "יו {name}! מה קורה?"
#, python-brace-format
msgid "Hey {name} how are you doing?"
msgstr ""
msgstr "היי {name} איך אתה מסתדר?"
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr ""
msgstr "יחידה {name} בקרבת מקום!"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr ""
msgstr "אוף ... להתראות {name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr ""
msgstr "{name} נעלם ..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr ""
msgstr "אופס ... {name} נעלם ."
#, python-brace-format
msgid "{name} missed!"
msgstr ""
msgstr "{name} התפספס!"
msgid "Missed!"
msgstr ""
msgstr "התפספס!"
msgid "Good friends are a blessing!"
msgstr ""
msgstr "חברים טובים זאת ברכה!"
msgid "I love my friends!"
msgstr ""
msgstr "אני אוהב את החברים שלי!"
msgid "Nobody wants to play with me ..."
msgstr ""
msgstr "אף אחד לא רוצה לשחק אית . . ."
msgid "I feel so alone ..."
msgstr ""
msgstr "אני מרגיש כל כך לבד . . ."
msgid "Where's everybody?!"
msgstr ""
msgstr "לאיפה כולם נעלמו?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr ""
msgstr "מנמנם למשך {secs}שניות ..."
msgid "Zzzzz"
msgstr ""
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
msgstr "ZzzZzzz ({secs}s)"
msgid "Good night."
msgstr ""
msgstr "לילה טוב"
msgid "Zzz"
msgstr ""
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr ""
msgstr "מחכה ל {secs}שניות ..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr ""
msgstr "מסתכל מסביב ({secs}שניות)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr ""
msgstr "היי {what} בוא נהיה חברים!"
#, python-brace-format
msgid "Associating to {what}"
msgstr ""
msgstr "מקשר את עצמי אל {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr ""
msgstr "יו יו {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr ""
msgstr "בדיוק החלטתי ש {mac} לא צריך חיבור אלחוטי"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr ""
msgstr "מסכל את האימות של {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr ""
msgstr "מוציא איסור על/מעיף {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr ""
msgstr "מגניב!, הצלחנו להשיג {num} לחיצות ידיים חדשות{plural}!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr ""
msgstr "יש לך {count} הודעות חדשות{plural}!"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr ""
msgstr "אופס!, משהו לא קרה כשורה ... מאתחל ..."
#, python-brace-format
msgid "Uploading data to {to} ..."
msgstr ""
msgstr "מעלה נתונים ל {to} ..."
#, python-brace-format
msgid "Downloading from {name} ..."
msgstr ""
msgstr "מוריד נתונים מ {name} ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr ""
msgstr "העפתי {num} תחנות\n"
msgid "Made >999 new friends\n"
msgstr ""
msgstr "הכרתי >999 חברים חדשים\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr ""
msgstr "הכרתי {num} חברים חדשים\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr ""
msgstr "השגתי {num} לחיצות ידיים\n"
msgid "Met 1 peer"
msgstr ""
msgstr "פגשתי שותף 1 "
#, python-brace-format
msgid "Met {num} peers"
msgstr ""
msgstr "פגשתי {num} שותפים"
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
msgstr "אני שלטתי במשך {duration} והצלחתי להעיף {deauthed} משתמשים! בדרך גם פגשתי "
"{associated} חברים חדשים ואכלתי {handshakes} לחיצות ידיים #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr ""
msgstr "שעות"
msgid "minutes"
msgstr ""
msgstr "דקות"
msgid "seconds"
msgstr ""
msgstr "שניות"
msgid "hour"
msgstr ""
msgstr "שעה"
msgid "minute"
msgstr ""
msgstr "דקה"
msgid "second"
msgstr ""
msgstr "שניה"

View File

@ -16,7 +16,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr ""
msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Ciao! Piacere Pwnagotchi! Caricamento ..."
@ -25,7 +25,7 @@ msgid "New day, new hunt, new pwns!"
msgstr "Nuovo giorno...nuovi handshakes!!!"
msgid "Hack the Planet!"
msgstr ""
msgstr "Hack il Pianeta"
msgid "AI ready."
msgstr "IA pronta."
@ -34,18 +34,18 @@ msgid "The neural network is ready."
msgstr "La rete neurale è pronta."
msgid "Generating keys, do not turn off ..."
msgstr ""
msgstr "Generazione di chiavi, non spegnere"
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Hey, il canale {channel} è libero! Il tuo AP ringrazia."
msgid "Reading last session logs ..."
msgstr ""
msgstr "Lettura dei log dell'ultima sessione ..."
#, python-brace-format
msgid "Read {lines_so_far} log lines so far ..."
msgstr ""
msgstr "Leggi le righe di log {lines_so_far} finora ..."
msgid "I'm bored ..."
msgstr "Che noia ..."
@ -54,7 +54,7 @@ msgid "Let's go for a walk!"
msgstr "Andiamo a fare una passeggiata!"
msgid "This is the best day of my life!"
msgstr "Questo è il più bel giorno della mia vita!!!!"
msgstr "Questo e il miglior giorno della mia vita!!!!"
msgid "Shitty day :/"
msgstr "Giorno di merda :/"
@ -72,22 +72,22 @@ msgid "Leave me alone ..."
msgstr "Mi sento così solo..."
msgid "I'm mad at you!"
msgstr ""
msgstr "sono arabiata con te"
msgid "I'm living the life!"
msgstr "Mi sento vivo!"
msgstr "sono viva la vita!"
msgid "I pwn therefore I am."
msgstr "Pwn ergo sum."
msgid "So many networks!!!"
msgstr "Qui è pieno di reti!"
msgstr "Qui pieno di reti!"
msgid "I'm having so much fun!"
msgstr "Mi sto divertendo tantissimo!"
msgid "My crime is that of curiosity ..."
msgstr ""
msgstr "Il mio crimine ? quello della curiosit?"
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
@ -95,15 +95,15 @@ msgstr "Ciao {name}! E' un piacere."
#, python-brace-format
msgid "Yo {name}! Sup?"
msgstr ""
msgstr "Yo {name} Come va"
#, python-brace-format
msgid "Hey {name} how are you doing?"
msgstr ""
msgstr "Ehi {name} come stai?"
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr "L'Unità {name} è vicina!"
msgstr "L'Unit {name} e vicina!"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
@ -111,30 +111,30 @@ msgstr "Uhm ... addio {name}, mi mancherai..."
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} se n'è andato ..."
msgstr "{name} se andato ..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Whoops ...{name} se n'è andato."
msgstr "Whoops ...{name} se andato."
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} è scomparso..."
msgstr "{name} scomparso..."
msgid "Missed!"
msgstr "Ehi! Dove sei andato!?"
msgid "Good friends are a blessing!"
msgstr ""
msgstr "Buoni amici sono una benedizione"
msgid "I love my friends!"
msgstr ""
msgstr "Amo i miei amici"
msgid "Nobody wants to play with me ..."
msgstr "Nessuno vuole giocare con me..."
msgid "I feel so alone ..."
msgstr "Mi sento così solo..."
msgstr "Mi sento cos solo..."
msgid "Where's everybody?!"
msgstr "Dove sono tutti?!"
@ -144,17 +144,17 @@ msgid "Napping for {secs}s ..."
msgstr "Schiaccio un pisolino per {secs}s ..."
msgid "Zzzzz"
msgstr ""
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
msgstr "ZzzZzzz ({secs}s)"
msgid "Good night."
msgstr ""
msgstr "Buona notte"
msgid "Zzz"
msgstr ""
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
@ -182,7 +182,7 @@ msgstr "Ho appena deciso che {mac} non necessita di WiFi!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr ""
msgstr "Annullamento dell'autenticazione {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
@ -201,11 +201,11 @@ msgstr "Ops, qualcosa è andato storto ... Riavvio ..."
#, python-brace-format
msgid "Uploading data to {to} ..."
msgstr ""
msgstr "Caricamento dei dati in {to}"
#, python-brace-format
msgid "Downloading from {name} ..."
msgstr ""
msgstr "Scaricamento da {name} ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
@ -255,4 +255,4 @@ msgid "minute"
msgstr "minuto"
msgid "second"
msgstr "secondo"
msgstr "secondo"

Binary file not shown.

View File

@ -10,98 +10,98 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-17 15:46+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Last-Translator: Foxy <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"Language: Portuguese (Brazil)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr ""
msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr ""
msgstr "Olá, Eu sou Pwnagotchi! Iniciando ..."
msgid "New day, new hunt, new pwns!"
msgstr ""
msgstr "Um novo dia, Uma nova caça e novos pwns!"
msgid "Hack the Planet!"
msgstr ""
msgstr "Burle o Planeta!"
msgid "AI ready."
msgstr ""
msgstr "IA pronta."
msgid "The neural network is ready."
msgstr ""
msgstr "A rede neural está pronta."
msgid "Generating keys, do not turn off ..."
msgstr ""
msgstr "Criando chaves, não desligue o sistema ..."
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr ""
msgstr "Ei, canal {channel} está livre! Seu AP vai agradecer."
msgid "Reading last session logs ..."
msgstr ""
msgstr "Lendo os logs da ultima sessão"
#, python-brace-format
msgid "Read {lines_so_far} log lines so far ..."
msgstr ""
msgstr "Leia {lines_so_far} linha de logs até agora ..."
msgid "I'm bored ..."
msgstr ""
msgstr "Eu estou entediado ..."
msgid "Let's go for a walk!"
msgstr ""
msgstr "Vamos ir numa caminhada!"
msgid "This is the best day of my life!"
msgstr ""
msgstr "Esse é o melhor dia da minha vida!"
msgid "Shitty day :/"
msgstr ""
msgstr "Dia ruim :/"
msgid "I'm extremely bored ..."
msgstr ""
msgstr "Eu estou extremamente entediado ..."
msgid "I'm very sad ..."
msgstr ""
msgstr "Eu estou muito triste ..."
msgid "I'm sad"
msgstr ""
msgstr "Eu estou triste"
msgid "Leave me alone ..."
msgstr ""
msgstr "Me deixe em paz ..."
msgid "I'm mad at you!"
msgstr ""
msgstr "Eu estou bravo com você!"
msgid "I'm living the life!"
msgstr ""
msgstr "Eu estou vivendo a vida!"
msgid "I pwn therefore I am."
msgstr ""
msgstr "Eu pwn então Eu sou."
msgid "So many networks!!!"
msgstr ""
msgstr "Tantas redes!!!"
msgid "I'm having so much fun!"
msgstr ""
msgstr "Eu estou tendo muita diversão"
msgid "My crime is that of curiosity ..."
msgstr ""
msgstr "Meu crime é de curiosidade ..."
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr ""
msgstr "Olá {name}! É bom em conhecê-lo"
#, python-brace-format
msgid "Yo {name}! Sup?"
msgstr ""
msgstr "Ei {name}! Como vai?"
#, python-brace-format
msgid "Hey {name} how are you doing?"
msgstr ""
msgstr "Ei {name} como você está indo?"
#, python-brace-format
msgid "Unit {name} is nearby!"
@ -121,115 +121,115 @@ msgstr ""
#, python-brace-format
msgid "{name} missed!"
msgstr ""
msgstr "{name} errou!"
msgid "Missed!"
msgstr ""
msgstr "Errei!"
msgid "Good friends are a blessing!"
msgstr ""
msgstr "Bom amigos são uma bensão!"
msgid "I love my friends!"
msgstr ""
msgstr "Eu amo meus amigos!"
msgid "Nobody wants to play with me ..."
msgstr ""
msgstr "Ninguém quer brincar comigo ..."
msgid "I feel so alone ..."
msgstr ""
msgstr "Estou me sentindo sozinho"
msgid "Where's everybody?!"
msgstr ""
msgstr "Onde está todo mundo?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr ""
msgstr "Tirando uma soneca por {secs}s ..."
msgid "Zzzzz"
msgstr ""
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
msgstr "ZzzZzzz ({secs}s)"
msgid "Good night."
msgstr ""
msgstr "Boa noite."
msgid "Zzz"
msgstr ""
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr ""
msgstr "Esperando por {secs}s ..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr ""
msgstr "Olhando por volta ({secs}s)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr ""
msgstr "Ei {what} vamos ser amigos!"
#, python-brace-format
msgid "Associating to {what}"
msgstr ""
msgstr "Associando para {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr ""
msgstr "Ei {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr ""
msgstr "Apenas decidindo que {mac} não precisa de WiFi!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr ""
msgstr "Desautenticando {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr ""
msgstr "Banindo {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr ""
msgstr "Legal, conseguimos {num} novos handshake{plural}!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr ""
msgstr "Você tem {count} novas messagem{plural}!"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr ""
msgstr "Oops, algo deu errado ... Reiniciando ..."
#, python-brace-format
msgid "Uploading data to {to} ..."
msgstr ""
msgstr "Enviando dados para {to} ..."
#, python-brace-format
msgid "Downloading from {name} ..."
msgstr ""
msgstr "Instalando para {name} ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr ""
msgstr "Expulsei {num} estações\n"
msgid "Made >999 new friends\n"
msgstr ""
msgstr "Fiz >999 novos amigos\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr ""
msgstr "Fiz {num} novos amigos\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr ""
msgstr "Peguei {num} handshakes\n"
msgid "Met 1 peer"
msgstr ""
msgstr "Encontrei 1 pessoa"
#, python-brace-format
msgid "Met {num} peers"
msgstr ""
msgstr "Encontrei {num} pessoas"
#, python-brace-format
msgid ""
@ -237,21 +237,24 @@ msgid ""
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
"Estou navegando há {duration} e expulsei {deauthed} clientes! Também conheci "
"{associamos} novos amigos e comi {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr ""
msgstr "horas"
msgid "minutes"
msgstr ""
msgstr "minutos"
msgid "seconds"
msgstr ""
msgstr "segundos"
msgid "hour"
msgstr ""
msgstr "hora"
msgid "minute"
msgstr ""
msgstr "minuto"
msgid "second"
msgstr ""
msgstr "segundo"

View File

@ -3,12 +3,12 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-17 15:46+0100\n"
"POT-Creation-Date: 2024-01-25 23:40+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -0,0 +1,73 @@
import pwnagotchi.plugins as plugins
import logging
import subprocess
import string
import os
'''
Aircrack-ng needed, to install:
> apt-get install aircrack-ng
'''
class AircrackOnly(plugins.Plugin):
__author__ = 'pwnagotchi [at] rossmarks [dot] uk'
__version__ = '1.0.1'
__license__ = 'GPL3'
__description__ = 'confirm pcap contains handshake/PMKID or delete it'
def __init__(self):
self.text_to_set = ""
self.options = dict()
def on_ready(self):
return
def on_loaded(self):
logging.info("aircrackonly plugin loaded")
if 'face' not in self.options:
self.options['face'] = '(>.<)'
check = subprocess.run(
'/usr/bin/dpkg -l aircrack-ng | grep aircrack-ng | awk \'{print $2, $3}\'', shell=True,
stdout=subprocess.PIPE)
check = check.stdout.decode('utf-8').strip()
if check != "aircrack-ng <none>":
logging.info("aircrackonly: Found " + check)
else:
logging.warning("aircrack-ng is not installed!")
def on_handshake(self, agent, filename, access_point, client_station):
display = agent.view()
to_delete = 0
handshake_found = 0
result = subprocess.run(('/usr/bin/aircrack-ng ' + filename + ' | grep "1 handshake" | awk \'{print $2}\''),
shell=True, stdout=subprocess.PIPE)
result = result.stdout.decode('utf-8').translate({ord(c): None for c in string.whitespace})
if result:
handshake_found = 1
logging.info("[AircrackOnly] contains handshake")
if handshake_found == 0:
result = subprocess.run(('/usr/bin/aircrack-ng ' + filename + ' | grep "PMKID" | awk \'{print $2}\''),
shell=True, stdout=subprocess.PIPE)
result = result.stdout.decode('utf-8').translate({ord(c): None for c in string.whitespace})
if result:
logging.info("[AircrackOnly] contains PMKID")
else:
to_delete = 1
if to_delete == 1:
os.remove(filename)
self.text_to_set = "Removed an uncrackable pcap"
logging.warning("Removed uncrackable pcap " + filename)
display.update(force=True)
def on_ui_update(self, ui):
if self.text_to_set:
ui.set('face', self.options['face'])
ui.set('status', self.text_to_set)
self.text_to_set = ""

View File

@ -130,7 +130,7 @@ def install(display, update):
source_path = "%s-%s" % (source_path, update['available'])
# setup.py is going to install data files for us
os.system("cd %s && pip3 install . --no-cache-dir --break-system-packages" % source_path)
os.system("cd %s && pip3 install . --break-system-packages" % source_path)
return True
@ -212,7 +212,7 @@ class AutoUpdate(plugins.Plugin):
if install(display, update):
num_installed += 1
else:
prev_status = '%d new update%c available!' % (num_updates, 's' if num_updates > 1 else '')
prev_status = '%d new update%s available!' % (num_updates, 's' if num_updates > 1 else '')
logging.info("[update] done")

View File

@ -11,10 +11,6 @@ from pwnagotchi import plugins
import pwnagotchi.ui.faces as faces
from pwnagotchi.bettercap import Client
from pwnagotchi.ui.components import Text
from pwnagotchi.ui.view import BLACK
import pwnagotchi.ui.fonts as fonts
class FixServices(plugins.Plugin):
__author__ = 'jayofelony'
@ -25,62 +21,39 @@ class FixServices(plugins.Plugin):
__help__ = """
Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG.
"""
__dependencies__ = {
'pip': ['scapy']
}
__defaults__ = {
'enabled': True,
}
def __init__(self):
self.options = dict()
self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed')
self.pattern2 = re.compile(r'wifi error while hopping to channel')
self.pattern3 = re.compile(r'Firmware has halted or crashed')
self.pattern4 = re.compile(r'error 400: could not find interface wlan0mon')
self.pattern1 = re.compile(r'wifi error while hopping to channel')
self.pattern2 = re.compile(r'Firmware has halted or crashed')
self.pattern3 = re.compile(r'error 400: could not find interface wlan0mon')
self.isReloadingMon = False
self.connection = None
self.LASTTRY = 0
self._status = "--"
self._count = 0
def on_loaded(self):
"""
Gets called when the plugin gets loaded
"""
self._status = "ld"
logging.info("[Fix_Services] plugin loaded.")
def on_ready(self, agent):
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10', '-k'],
stdout=subprocess.PIPE).stdout))[-10:])
last_lines = self.get_last_lines('journalctl', ['-n10', '-k'], 10)
try:
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
logging.debug("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
if ",UP," in str(cmd_output):
logging.info("wlan0mon is up.")
self._status = "up"
if len(self.pattern.findall(last_lines)) >= 3:
self._status = "XX"
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Blind-Bug detected. Restarting.')
display.update(force=True)
logging.info('[Fix_Services] Blind-Bug detected. Restarting.')
try:
self._tryTurningItOffAndOnAgain(agent)
except Exception as err:
logging.warning("[Fix_Services turnOffAndOn] %s" % repr(err))
else:
logging.info("[Fix_Services] Logs look good!")
self._status = ""
logging.info("[Fix_Services] Logs look good!")
except Exception as err:
logging.error("[Fix_Services ip link show wlan0mon]: %s" % repr(err))
try:
self._status = "xx"
self._tryTurningItOffAndOnAgain(agent)
except Exception as err:
logging.error("[Fix_Services OffNOn]: %s" % repr(err))
@ -109,14 +82,23 @@ class FixServices(plugins.Plugin):
logging.error("[Fix_Services]SYSLOG wifi.recon flip fail: %s" % err)
self._tryTurningItOffAndOnAgain(agent)
def get_last_lines(self, command, args, n):
try:
process = subprocess.Popen([command] + args, stdout=subprocess.PIPE)
output = TextIOWrapper(process.stdout)
lines = output.readlines()
last_n_lines = ''.join(lines[-n:])
return last_n_lines
except Exception as e:
print(f"Error occurred: {e}")
return None
def on_epoch(self, agent, epoch, epoch_data):
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10', '-k'],
stdout=subprocess.PIPE).stdout))[-10:])
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
stdout=subprocess.PIPE).stdout))[-10:])
other_other_last_lines = ''.join(
list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/var/log/pwnagotchi.log'],
stdout=subprocess.PIPE).stdout))[-10:])
last_lines = self.get_last_lines('journalctl', ['-n10', '-k'], 10)
other_last_lines = self.get_last_lines('journalctl', ['-n10'], 10)
other_other_last_lines = self.get_last_lines('tail', ['-n10', '/home/pi/logs/pwnagotchi.log'], 10)
# don't check if we ran a reset recently
logging.debug("[Fix_Services]**** epoch")
if time.time() - self.LASTTRY > 180:
@ -126,21 +108,8 @@ class FixServices(plugins.Plugin):
logging.debug("[Fix_Services]**** checking")
# Look for pattern 1
if len(self.pattern.findall(last_lines)) >= 3:
logging.info("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Blind-Bug detected. Restarting.')
display.update(force=True)
logging.info('[Fix_Services] Blind-Bug detected. Restarting.')
try:
self._tryTurningItOffAndOnAgain(agent)
except Exception as err:
logging.warning("[Fix_Services] TTOAOA: %s" % repr(err))
# Look for pattern 2
elif len(self.pattern2.findall(other_last_lines)) >= 5:
logging.info("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
if len(self.pattern1.findall(other_last_lines)) >= 5:
logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Wifi channel stuck. Restarting recon.')
@ -153,7 +122,6 @@ class FixServices(plugins.Plugin):
logging.info("[Fix_Services] wifi.recon flip: success!")
if display:
display.update(force=True, new_data={"status": "Wifi recon flipped!",
"brcmfmac_status": self._status,
"face": faces.COOL})
else:
print("Wifi recon flipped\nthat was easy!")
@ -163,8 +131,8 @@ class FixServices(plugins.Plugin):
except Exception as err:
logging.error("[Fix_Services wifi.recon flip] %s" % repr(err))
# Look for pattern 3
elif len(self.pattern3.findall(other_last_lines)) >= 1:
# Look for pattern 2
elif len(self.pattern2.findall(other_last_lines)) >= 1:
logging.info("[Fix_Services] Firmware has halted or crashed. Restarting wlan0mon.")
if hasattr(agent, 'view'):
display = agent.view()
@ -173,12 +141,12 @@ class FixServices(plugins.Plugin):
try:
# Run the monstart command to restart wlan0mon
cmd_output = subprocess.check_output("monstart", shell=True)
logging.info("[Fix_Services monstart]: %s" % repr(cmd_output))
logging.debug("[Fix_Services monstart]: %s" % repr(cmd_output))
except Exception as err:
logging.error("[Fix_Services monstart]: %s" % repr(err))
# Look for pattern 4
elif len(self.pattern4.findall(other_other_last_lines)) >= 3:
# Look for pattern 3
elif len(self.pattern3.findall(other_other_last_lines)) >= 3:
logging.info("[Fix_Services] wlan0 is down!")
if hasattr(agent, 'view'):
display = agent.view()
@ -187,7 +155,7 @@ class FixServices(plugins.Plugin):
try:
# Run the monstart command to restart wlan0mon
cmd_output = subprocess.check_output("monstart", shell=True)
logging.info("[Fix_Services monstart]: %s" % repr(cmd_output))
logging.debug("[Fix_Services monstart]: %s" % repr(cmd_output))
except Exception as err:
logging.error("[Fix_Services monstart]: %s" % repr(err))
@ -223,12 +191,11 @@ class FixServices(plugins.Plugin):
self.isReloadingMon = True
self.LASTTRY = time.time()
self._status = "BL"
if hasattr(connection, 'view'):
display = connection.view()
if display:
display.update(force=True, new_data={"status": "I'm blind! Try turning it off and on again",
"brcmfmac_status": self._status, "face": faces.BORED})
"face": faces.BORED})
else:
display = None
@ -244,7 +211,7 @@ class FixServices(plugins.Plugin):
# is it up?
try:
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
logging.debug("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
if ",UP," in str(cmd_output):
logging.info("wlan0mon is up. Skip reset?")
# not reliable, so don't skip just yet
@ -271,7 +238,6 @@ class FixServices(plugins.Plugin):
try:
cmd_output = subprocess.check_output("monstop", shell=True)
self._status = "dn"
self.logPrintView("info", "[Fix_Services] wlan0mon down and deleted: %s" % cmd_output,
display, {"status": "wlan0mon d-d-d-down!", "face": faces.BORED})
except Exception as nope:
@ -291,7 +257,6 @@ class FixServices(plugins.Plugin):
cmd_output = subprocess.check_output("sudo modprobe -r brcmfmac", shell=True)
self.logPrintView("info", "[Fix_Services] unloaded brcmfmac", display,
{"status": "Turning it off #%s" % tries, "face": faces.SMART})
self._status = "ul"
time.sleep(1 + tries)
# reload the module
@ -300,7 +265,6 @@ class FixServices(plugins.Plugin):
cmd_output = subprocess.check_output("sudo modprobe brcmfmac", shell=True)
self.logPrintView("info", "[Fix_Services] reloaded brcmfmac")
self._status = "rl"
time.sleep(10 + 4 * tries) # give it some time for wlan device to stabilize, or whatever
# success! now make the mon0
@ -308,24 +272,20 @@ class FixServices(plugins.Plugin):
cmd_output = subprocess.check_output("monstart", shell=True)
self.logPrintView("info", "[Fix_Services interface add wlan0mon] worked #%s: %s"
% (tries, cmd_output))
self._status = "up"
time.sleep(tries + 5)
try:
# try accessing mon0 in bettercap
result = connection.run("set wifi.interface wlan0mon")
if "success" in result:
logging.info("[Fix_Services set wifi.interface wlan0mon] worked!")
self._status = ""
self._count = self._count + 1
time.sleep(1)
# stop looping and get back to recon
break
else:
logging.info(
"[Fix_Services set wifi.interfaceface wlan0mon] failed? %s" % repr(result))
logging.debug("[Fix_Services set wifi.interfaceface wlan0mon] failed? %s" % repr(result))
except Exception as err:
logging.info(
"[Fix_Services set wifi.interface wlan0mon] except: %s" % repr(err))
logging.debug("[Fix_Services set wifi.interface wlan0mon] except: %s" % repr(err))
except Exception as cerr: #
if not display:
print("failed loading wlan0mon attempt #%s: %s" % (tries, repr(cerr)))
@ -354,7 +314,6 @@ class FixServices(plugins.Plugin):
if tries < 3:
if display:
display.update(force=True, new_data={"status": "And back on again...",
"brcmfmac_status": self._status,
"face": faces.INTENSE})
else:
print("And back on again...")
@ -370,14 +329,12 @@ class FixServices(plugins.Plugin):
result = connection.run("wifi.clear; wifi.recon on")
if "success" in result: # and result["success"] is True:
self._status = ""
if display:
display.update(force=True, new_data={"status": "I can see again! (probably)",
"brcmfmac_status": self._status,
"face": faces.HAPPY})
else:
print("I can see again")
logging.info("[Fix_Services] wifi.recon on")
logging.debug("[Fix_Services] wifi.recon on")
self.LASTTRY = time.time() + 120 # 2-minute pause until next time.
else:
logging.error("[Fix_Services] wifi.recon did not start up")
@ -388,34 +345,12 @@ class FixServices(plugins.Plugin):
logging.error("[Fix_Services wifi.recon on] %s" % repr(err))
pwnagotchi.reboot()
# called to setup the ui elements
def on_ui_setup(self, ui):
with ui._lock:
# add custom UI elements
if "position" in self.options:
pos = self.options['position'].split(',')
pos = [int(x.strip()) for x in pos]
else:
pos = (ui.width() / 2 + 35, ui.height() - 11)
logging.info("Got here")
ui.add_element('brcmfmac_status', Text(color=BLACK, value='--', position=pos, font=fonts.Small))
# called when the ui is updated
def on_ui_update(self, ui):
# update those elements
if self._status:
ui.set('brcmfmac_status', "wlan0mon %s" % self._status)
else:
ui.set('brcmfmac_status', "rst#%s" % self._count)
def on_unload(self, ui):
with ui._lock:
try:
ui.remove_element('brcmfmac_status')
logging.info("[Fix_Services] unloaded")
except Exception as err:
logging.info("[Fix_Services] unload err %s " % repr(err))
logging.error("[Fix_Services] unload err %s " % repr(err))
pass

View File

@ -14,19 +14,15 @@ import zipfile
class GdriveSync(plugins.Plugin):
__author__ = '@jayofelony'
__version__ = '1.0'
__version__ = '1.2'
__license__ = 'GPL3'
__description__ = 'A plugin to backup various pwnagotchi files and folders to Google Drive. Once every hour from loading plugin.'
__dependencies__ = {
'pip': ['pydrive2']
}
def __init__(self):
self.options = dict()
self.lock = Lock()
self.internet = False
self.ready = False
self.drive = None
self.status = StatusFile('/root/.gdrive-backup')
self.backup = True
self.backupfiles = [
@ -38,12 +34,11 @@ class GdriveSync(plugins.Plugin):
'/etc/pwnagotchi'
]
def on_loaded(self, agent):
def on_loaded(self):
"""
Called when the plugin is loaded
"""
# client_secrets.json needs to be not empty
display = agent.view()
if os.stat("/root/client_secrets.json").st_size == 0:
logging.error("[gDriveSync] /root/client_secrets.json is empty. Please RTFM!")
return
@ -78,25 +73,24 @@ class GdriveSync(plugins.Plugin):
# logging.warning(f"[gDriveSync] No files found in the folder with ID {root_file_list} and {pwnagotchi_file_list}")
if self.options['backupfiles'] is not None:
self.backupfiles = self.backupfiles + self.options['backupfiles']
self.backup_files(self.backupfiles, '/backup')
self.backup_files(self.backupfiles, '/home/pi/backup')
# Create a zip archive of the /backup folder
zip_file_path = os.path.join('/home/pi', 'backup.zip')
with zipfile.ZipFile(zip_file_path, 'w') as zip_ref:
for root, dirs, files in os.walk('/backup'):
for root, dirs, files in os.walk('/home/pi/backup'):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, '/backup')
arcname = os.path.relpath(file_path, '/home/pi/backup')
zip_ref.write(file_path, arcname=arcname)
# Upload the zip archive to Google Drive
self.upload_to_gdrive(zip_file_path, self.get_folder_id_by_name(self.drive, self.options['backup_folder']))
display.on_uploading("Google Drive")
self.backup = True
self.status.update()
# Specify the local backup path
local_backup_path = '/'
local_backup_path = '/home/pi/'
# Download the zip archive from Google Drive
zip_file_id = self.get_latest_backup_file_id(self.options['backup_folder'])
@ -104,7 +98,6 @@ class GdriveSync(plugins.Plugin):
zip_file = self.drive.CreateFile({'id': zip_file_id})
zip_file.GetContentFile(os.path.join(local_backup_path, 'backup.zip'))
display.on_downloading("Google Drive")
logging.info("[gDriveSync] Downloaded backup.zip from Google Drive")
# Extract the zip archive to the root directory
@ -112,9 +105,12 @@ class GdriveSync(plugins.Plugin):
zip_ref.extractall('/')
self.status.update()
os.remove("/backup")
# Reboot so we can start opwngrid with the backup id
pwnagotchi.reboot()
shutil.rmtree("/home/pi/backup")
os.remove("/home/pi/backup.zip")
self.ready = True
logging.info("[gdrivesync] loaded")
# Restart so we can start opwngrid with the backup id
pwnagotchi.restart("AUTO")
# all set, gdriveSync is ready to run
self.ready = True
@ -186,15 +182,15 @@ class GdriveSync(plugins.Plugin):
logging.info("[gdrivesync] new handshake captured, backing up to gdrive")
if self.options['backupfiles'] is not None:
self.backupfiles = self.backupfiles + self.options['backupfiles']
self.backup_files(self.backupfiles, '/backup')
self.backup_files(self.backupfiles, '/home/pi/backup')
# Create a zip archive of the /backup folder
zip_file_path = os.path.join('/home/pi', 'backup.zip')
with zipfile.ZipFile(zip_file_path, 'w') as zip_ref:
for root, dirs, files in os.walk('/backup'):
for root, dirs, files in os.walk('/home/pi/backup'):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, '/backup')
arcname = os.path.relpath(file_path, '/home/pi/backup')
zip_ref.write(file_path, arcname=arcname)
# Upload the zip archive to Google Drive
@ -203,7 +199,7 @@ class GdriveSync(plugins.Plugin):
# Cleanup the local zip file
os.remove(zip_file_path)
os.remove("/backup")
shutil.rmtree("/home/pi/backup")
self.status.update()
display = agent.view()
display.update(force=True, new_data={'Backing up to gdrive ...'})

View File

@ -20,6 +20,7 @@ class GPS(plugins.Plugin):
def __init__(self):
self.running = False
self.coordinates = None
self.options = dict()
def on_loaded(self):
logging.info(f"gps plugin loaded for {self.options['device']}")

View File

@ -58,8 +58,9 @@ class Grid(plugins.Plugin):
self.total_messages = 0
self.lock = Lock()
def is_excluded(self, what):
for skip in self.options['exclude']:
def is_excluded(self, what, agent):
config = agent.config()
for skip in config['main']['whitelist']:
skip = skip.lower()
what = what.lower()
if skip in what or skip.replace(':', '') in what:
@ -87,6 +88,7 @@ class Grid(plugins.Plugin):
def check_handshakes(self, agent):
logging.debug("checking pcaps")
config = agent.config()
pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap"))
num_networks = len(pcap_files)
@ -98,19 +100,19 @@ class Grid(plugins.Plugin):
if self.options['report']:
logging.info("grid: %d new networks to report" % num_new)
logging.debug("self.options: %s" % self.options)
logging.debug(" exclude: %s" % self.options['exclude'])
logging.debug(" exclude: %s" % config['main']['whitelist'])
for pcap_file in pcap_files:
net_id = os.path.basename(pcap_file).replace('.pcap', '')
if net_id not in reported:
if self.is_excluded(net_id):
if self.is_excluded(net_id, agent):
logging.debug("skipping %s due to exclusion filter" % pcap_file)
self.set_reported(reported, net_id)
continue
essid, bssid = parse_pcap(pcap_file)
if bssid:
if self.is_excluded(essid) or self.is_excluded(bssid):
if self.is_excluded(essid, agent) or self.is_excluded(bssid, agent):
logging.debug("not reporting %s due to exclusion filter" % pcap_file)
self.set_reported(reported, net_id)
else:

View File

@ -0,0 +1,179 @@
import logging
import subprocess
import os
import json
import pwnagotchi.plugins as plugins
from threading import Lock
'''
hcxpcapngtool needed, to install:
> git clone https://github.com/ZerBea/hcxtools.git
> cd hcxtools
> apt-get install libcurl4-openssl-dev libssl-dev zlib1g-dev
> make
> sudo make install
'''
class Hashie(plugins.Plugin):
__author__ = 'Jayofelony'
__version__ = '1.0.4'
__license__ = 'GPL3'
__description__ = '''
Attempt to automatically convert pcaps to a crackable format.
If successful, the files containing the hashes will be saved
in the same folder as the handshakes.
The files are saved in their respective Hashcat format:
- EAPOL hashes are saved as *.22000
- PMKID hashes are saved as *.16800
All PCAP files without enough information to create a hash are
stored in a file that can be read by the webgpsmap plugin.
Why use it?:
- Automatically convert handshakes to crackable formats!
We dont all upload our hashes online ;)
- Repair PMKID handshakes that hcxpcapngtool misses
- If running at time of handshake capture, on_handshake can
be used to improve the chance of the repair succeeding
- Be a completionist! Not enough packets captured to crack a network?
This generates an output file for the webgpsmap plugin, use the
location data to revisit networks you need more packets for!
Additional information:
- Currently requires hcxpcapngtool compiled and installed
- Attempts to repair PMKID hashes when hcxpcapngtool cant find the SSID
- hcxpcapngtool sometimes has trouble extracting the SSID, so we
use the raw 16800 output and attempt to retrieve the SSID via tcpdump
- When access_point data is available (on_handshake), we leverage
the reported AP name and MAC to complete the hash
- The repair is very basic and could certainly be improved!
Todo:
Make it so users dont need hcxpcapngtool (unless it gets added to the base image)
Phase 1: Extract/construct 22000/16800 hashes through tcpdump commands
Phase 2: Extract/construct 22000/16800 hashes entirely in python
Improve the code, a lot
'''
def __init__(self):
self.lock = Lock()
self.options = dict()
def on_loaded(self):
logging.info("[Hashie] Plugin loaded")
def on_unloaded(self):
logging.info("[Hashie] Plugin unloaded")
# called when everything is ready and the main loop is about to start
def on_ready(self, agent):
config = agent.config()
handshake_dir = config['bettercap']['handshakes']
logging.info('[Hashie] Starting batch conversion of pcap files')
with self.lock:
self._process_stale_pcaps(handshake_dir)
def on_handshake(self, agent, filename, access_point, client_station):
with self.lock:
handshake_status = []
fullpathNoExt = filename.split('.')[0]
name = filename.split('/')[-1:][0].split('.')[0]
if os.path.isfile(fullpathNoExt + '.22000'):
handshake_status.append('Already have {}.22000 (EAPOL)'.format(name))
elif self._writeEAPOL(filename):
handshake_status.append('Created {}.22000 (EAPOL) from pcap'.format(name))
if os.path.isfile(fullpathNoExt + '.16800'):
handshake_status.append('Already have {}.16800 (PMKID)'.format(name))
elif self._writePMKID(filename):
handshake_status.append('Created {}.16800 (PMKID) from pcap'.format(name))
if handshake_status:
logging.info('[Hashie] Good news:\n\t' + '\n\t'.join(handshake_status))
def _writeEAPOL(self, fullpath):
fullpathNoExt = fullpath.split('.')[0]
filename = fullpath.split('/')[-1:][0].split('.')[0]
subprocess.getoutput('hcxpcapngtool -o {}.22000 {} >/dev/null 2>&1'.format(fullpathNoExt, fullpath))
if os.path.isfile(fullpathNoExt + '.22000'):
logging.debug('[Hashie] [+] EAPOL Success: {}.22000 created'.format(filename))
return True
return False
def _writePMKID(self, fullpath):
fullpathNoExt = fullpath.split('.')[0]
filename = fullpath.split('/')[-1:][0].split('.')[0]
subprocess.getoutput('hcxpcapngtool -o {}.16800 {} >/dev/null 2>&1'.format(fullpathNoExt, fullpath))
if os.path.isfile(fullpathNoExt + '.16800'):
logging.debug('[Hashie] [+] PMKID Success: {}.16800 created'.format(filename))
return True
return False
def _process_stale_pcaps(self, handshake_dir):
handshakes_list = [os.path.join(handshake_dir, filename) for filename in os.listdir(handshake_dir) if filename.endswith('.pcap')]
failed_jobs = []
successful_jobs = []
lonely_pcaps = []
for num, handshake in enumerate(handshakes_list):
fullpathNoExt = handshake.split('.')[0]
pcapFileName = handshake.split('/')[-1:][0]
if not os.path.isfile(fullpathNoExt + '.22000'): # if no 22000, try
if self._writeEAPOL(handshake):
successful_jobs.append('22000: ' + pcapFileName)
else:
failed_jobs.append('22000: ' + pcapFileName)
if not os.path.isfile(fullpathNoExt + '.16800'): # if no 16800, try
if self._writePMKID(handshake):
successful_jobs.append('16800: ' + pcapFileName)
else:
failed_jobs.append('16800: ' + pcapFileName)
if not os.path.isfile(fullpathNoExt + '.22000'): # if no 16800 AND no 22000
lonely_pcaps.append(handshake)
logging.debug('[hashie] Batch job: added {} to lonely list'.format(pcapFileName))
if ((num + 1) % 50 == 0) or (num + 1 == len(handshakes_list)): # report progress every 50, or when done
logging.info('[Hashie] Batch job: {}/{} done ({} fails)'.format(num + 1, len(handshakes_list), len(lonely_pcaps)))
if successful_jobs:
logging.info('[Hashie] Batch job: {} new handshake files created'.format(len(successful_jobs)))
if lonely_pcaps:
logging.info('[Hashie] Batch job: {} networks without enough packets to create a hash'.format(len(lonely_pcaps)))
self._getLocations(lonely_pcaps)
def _getLocations(self, lonely_pcaps):
# export a file for webgpsmap to load
with open('/root/.incompletePcaps', 'w') as isIncomplete:
count = 0
for pcapFile in lonely_pcaps:
filename = pcapFile.split('/')[-1:][0] # keep extension
fullpathNoExt = pcapFile.split('.')[0]
isIncomplete.write(filename + '\n')
if os.path.isfile(fullpathNoExt + '.gps.json') or os.path.isfile(fullpathNoExt + '.geo.json'):
count += 1
if count != 0:
logging.info('[Hashie] Used {} GPS/GEO files to find lonely networks, '
'go check webgpsmap! ;)'.format(str(count)))
else:
logging.info('[Hashie] Could not find any GPS/GEO files '
'for the lonely networks'.format(str(count)))
def _getLocationsCSV(self, lonely_pcaps):
# in case we need this later, export locations manually to CSV file, needs try/catch format/etc.
locations = []
for pcapFile in lonely_pcaps:
filename = pcapFile.split('/')[-1:][0].split('.')[0]
fullpathNoExt = pcapFile.split('.')[0]
if os.path.isfile(fullpathNoExt + '.gps.json'):
with open(fullpathNoExt + '.gps.json', 'r') as tempFileA:
data = json.load(tempFileA)
locations.append(filename + ',' + str(data['Latitude']) + ',' + str(data['Longitude']) + ',50')
elif os.path.isfile(fullpathNoExt + '.geo.json'):
with open(fullpathNoExt + '.geo.json', 'r') as tempFileB:
data = json.load(tempFileB)
locations.append(
filename + ',' + str(data['location']['lat']) + ',' + str(data['location']['lng']) + ',' + str(data['accuracy']))
if locations:
with open('/root/locations.csv', 'w') as tempFileD:
for loc in locations:
tempFileD.write(loc + '\n')
logging.info('[Hashie] Used {} GPS/GEO files to find lonely networks, '
'load /root/locations.csv into a mapping app and go say hi!'.format(len(locations)))

View File

@ -141,7 +141,7 @@ class MemTemp(plugins.Plugin):
elif ui.is_inky():
h_pos = (140, 68)
v_pos = (160, 54)
elif ui.is_waveshare27inch():
elif ui.is_waveshare2in7():
h_pos = (192, 138)
v_pos = (211, 122)
else:

View File

@ -24,6 +24,7 @@ class NetPos(plugins.Plugin):
self.skip = list()
self.ready = False
self.lock = threading.Lock()
self.options = dict()
def on_loaded(self):
if 'api_key' not in self.options or ('api_key' in self.options and not self.options['api_key']):

View File

@ -25,6 +25,7 @@ class OnlineHashCrack(plugins.Plugin):
self.report = StatusFile('/root/.ohc_uploads', data_format='json')
self.skip = list()
self.lock = Lock()
self.options = dict()
def on_loaded(self):
"""
@ -34,13 +35,9 @@ class OnlineHashCrack(plugins.Plugin):
logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
return
if 'whitelist' not in self.options:
self.options['whitelist'] = list()
self.ready = True
logging.info("OHC: OnlineHashCrack plugin loaded.")
def _upload_to_ohc(self, path, timeout=30):
"""
Uploads the file to onlinehashcrack.com
@ -78,7 +75,6 @@ class OnlineHashCrack(plugins.Plugin):
except OSError as os_e:
raise os_e
def on_webhook(self, path, request):
import requests
from flask import redirect
@ -87,7 +83,6 @@ class OnlineHashCrack(plugins.Plugin):
r = s.post('https://www.onlinehashcrack.com/dashboard', data={'emailTasks': self.options['email'], 'submit': ''})
return redirect(r.url, code=302)
def on_internet_available(self, agent):
"""
Called in manual mode when there's internet connectivity
@ -105,7 +100,7 @@ class OnlineHashCrack(plugins.Plugin):
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if
filename.endswith('.pcap')]
# pull out whitelisted APs
handshake_paths = remove_whitelisted(handshake_paths, self.options['whitelist'])
handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist'])
handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
if handshake_new:
logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onlinehashcrack.com")

View File

@ -1,39 +0,0 @@
import logging
import requests
import pwnagotchi.plugins as plugins
'''
You need an bluetooth connection to your android phone which is running PAW server with the GPS "hack" from Systemik and edited by shaynemk
GUIDE HERE: https://community.pwnagotchi.ai/t/setting-up-paw-gps-on-android
'''
class PawGPS(plugins.Plugin):
__author__ = 'leont'
__version__ = '1.0.1'
__name__ = 'pawgps'
__license__ = 'GPL3'
__description__ = 'Saves GPS coordinates whenever an handshake is captured. The GPS data is get from PAW on android.'
def on_loaded(self):
logging.info("[paw-gps] plugin loaded")
if 'ip' not in self.options or ('ip' in self.options and self.options['ip'] is None) or (len('ip' in self.options and self.options['ip']) is 0):
logging.info("[paw-gps] no IP Address defined in the config file, will uses paw server default (192.168.44.1:8080)")
def on_handshake(self, agent, filename, access_point, client_station):
if 'ip' not in self.options or ('ip' in self.options and self.options['ip'] is None or (len('ip' in self.options and self.options['ip']) is 0)):
ip = "192.168.44.1:8080"
else:
ip = self.options['ip']
try:
gps = requests.get('http://' + ip + '/gps.xhtml')
try:
gps_filename = filename.replace('.pcap', '.paw-gps.json')
logging.info("[paw-gps] saving GPS data to %s" % (gps_filename))
with open(gps_filename, 'w+t') as f:
f.write(gps.text)
except Exception as error:
logging.error(f"[paw-gps] encountered error while saving gps data: {error}")
except Exception as error:
logging.error(f"[paw-gps] encountered error while getting gps data: {error}")

View File

@ -1,14 +1,20 @@
# Based on UPS Lite v1.1 from https://github.com/xenDE
# Made specifically to address the problems caused by the hardware changes in 1.3. Oh yeah I also removed the auto-shutdown feature because it's kind of broken.
#
# functions for get UPS status - needs enable "i2c" in raspi-config
# To setup, see page six of this manual to see how to enable i2c:
# https://github.com/linshuqin329/UPS-Lite/blob/master/UPS-Lite_V1.3_CW2015/Instructions%20for%20UPS-Lite%20V1.3.pdf
#
# https://github.com/linshuqin329/UPS-Lite
# Follow page seven, install the dependencies (python-smbus) and copy this script over for later use:
# https://github.com/linshuqin329/UPS-Lite/blob/master/UPS-Lite_V1.3_CW2015/UPS_Lite_V1.3_CW2015.py
#
# For Raspberry Pi Zero Ups Power Expansion Board with Integrated Serial Port S3U4
# https://www.ebay.de/itm/For-Raspberry-Pi-Zero-Ups-Power-Expansion-Board-with-Integrated-Serial-Port-S3U4/323873804310
# https://www.aliexpress.com/item/32888533624.html
# Now, install this plugin by copying this to the 'available-plugins' folder in your pwnagotchi, install and enable the plugin with the commands:
# sudo pwnagotchi plugins install upslite_plugin_1_3
# sudo pwnagotchi plugins enable upslite_plugin_1_3
#
# To display external power supply status you need to bridge the necessary pins on the UPS-Lite board. See instructions in the UPS-Lite repo.
# Now restart raspberry pi. Once back up ensure upslite_plugin_1_3 plugin is turned on in the WebUI. If there is still '0%' on your battery meter
# run the script we saved earlier and ensure that the pwnagotchi is plugged in both at the battery and the raspberry pi. The script should start trying to
# read the battery, and should be successful once there's a USB cable running power to the battery supply.
import logging
import struct
@ -20,6 +26,11 @@ import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.components import LabeledValue
from pwnagotchi.ui.view import BLACK
CW2015_ADDRESS = 0X62
CW2015_REG_VCELL = 0X02
CW2015_REG_SOC = 0X04
CW2015_REG_MODE = 0X0A
# TODO: add enable switch in config.yml an cleanup all to the best place
class UPS:
@ -31,8 +42,7 @@ class UPS:
def voltage(self):
try:
address = 0x36
read = self._bus.read_word_data(address, 2)
read = self._bus.read_word_data(CW2015_ADDRESS, CW2015_REG_VCELL)
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
return swapped * 1.25 / 1000 / 16
except:
@ -41,7 +51,7 @@ class UPS:
def capacity(self):
try:
address = 0x36
read = self._bus.read_word_data(address, 4)
read = self._bus.read_word_data(CW2015_ADDRESS, CW2015_REG_SOC)
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
return swapped / 256
except:
@ -57,10 +67,10 @@ class UPS:
class UPSLite(plugins.Plugin):
__author__ = 'evilsocket@gmail.com'
__version__ = '1.0.0'
__author__ = 'marbasec'
__version__ = '1.3.0'
__license__ = 'GPL3'
__description__ = 'A plugin that will add a voltage indicator for the UPS Lite v1.1'
__description__ = 'A plugin that will add a voltage indicator for the UPS Lite v1.3'
def __init__(self):
self.ups = None
@ -69,7 +79,7 @@ class UPSLite(plugins.Plugin):
self.ups = UPS()
def on_ui_setup(self, ui):
ui.add_element('ups', LabeledValue(color=BLACK, label='UPS', value='0%/0V', position=(ui.width() / 2 + 15, 0),
ui.add_element('ups', LabeledValue(color=BLACK, label='UPS', value='0%', position=(ui.width() / 2 + 15, 0),
label_font=fonts.Bold, text_font=fonts.Medium))
def on_unload(self, ui):
@ -80,7 +90,3 @@ class UPSLite(plugins.Plugin):
capacity = self.ups.capacity()
charging = self.ups.charging()
ui.set('ups', "%2i%s" % (capacity, charging))
if capacity <= self.options['shutdown']:
logging.info('[ups_lite] Empty battery (<= %s%%): shuting down' % self.options['shutdown'])
ui.update(force=True, new_data={'status': 'Battery exhausted, bye ...'})
pwnagotchi.shutdown()

View File

@ -1,9 +1,10 @@
import sys
import pwnagotchi.plugins as plugins
import logging
import os
import json
import re
import datetime
from flask import Response
from functools import lru_cache
from dateutil.parser import parse
@ -22,6 +23,7 @@ from dateutil.parser import parse
'''
class Webgpsmap(plugins.Plugin):
__author__ = 'https://github.com/xenDE and https://github.com/dadav'
__version__ = '1.4.0'
@ -103,7 +105,7 @@ class Webgpsmap(plugins.Plugin):
response_status = 200
response_mimetype = "application/xhtml+xml"
response_header_contenttype = 'text/html'
response_header_contentdisposition = 'attachment; filename=webgpsmap.html';
response_header_contentdisposition = 'attachment; filename=webgpsmap.html'
except Exception as error:
logging.error(f"[webgpsmap] on_webhook offlinemap: error: {error}")
return
@ -149,7 +151,6 @@ class Webgpsmap(plugins.Plugin):
def _get_pos_from_file(self, path):
return PositionFile(path)
def load_gps_from_dir(self, gpsdir, newest_only=False):
"""
Parses the gps-data from disk
@ -160,13 +161,9 @@ class Webgpsmap(plugins.Plugin):
logging.info(f"[webgpsmap] scanning {handshake_dir}")
all_files = os.listdir(handshake_dir)
#print(all_files)
all_pcap_files = [os.path.join(handshake_dir, filename)
for filename in all_files
if filename.endswith('.pcap')
]
# print(all_files)
all_pcap_files = [os.path.join(handshake_dir, filename) for filename in all_files if filename.endswith('.pcap')]
all_geo_or_gps_files = []
for filename_pcap in all_pcap_files:
filename_base = filename_pcap[:-5] # remove ".pcap"
@ -300,7 +297,6 @@ class PositionFile:
return parsed_ssid.groups()[0]
return None
def json(self):
"""
returns the parsed json

View File

@ -3,6 +3,7 @@ import logging
import json
import csv
import requests
import pwnagotchi
from io import StringIO
from datetime import datetime
@ -24,7 +25,11 @@ def _extract_gps_data(path):
with open(path, 'r') as json_file:
tempJson = json.load(json_file)
d = datetime.utcfromtimestamp(int(tempJson["ts"]))
return {"Latitude": tempJson["location"]["lat"], "Longitude": tempJson["location"]["lng"], "Altitude": 10, "Updated": d.strftime('%Y-%m-%dT%H:%M:%S.%f')}
return {"Latitude": tempJson["location"]["lat"],
"Longitude": tempJson["location"]["lng"],
"Altitude": 10,
"Accuracy": tempJson["accuracy"],
"Updated": d.strftime('%Y-%m-%dT%H:%M:%S.%f')}
else:
with open(path, 'r') as json_file:
return json.load(json_file)
@ -38,7 +43,7 @@ def _format_auth(data):
out = ""
for auth in data:
out = f"{out}[{auth}]"
return out
return [f"{auth}" for auth in data]
def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
@ -47,10 +52,10 @@ def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
"""
dummy = StringIO()
# write kismet header
dummy.write(f"WigleWifi-1.6,appRelease={plugin_version},model=pwnagotchi,release={__pwnagotchi_version__},"
f"device={pwnagotchi.name()},display=kismet,board=RaspberryPi,brand=pwnagotchi,star=Sol,body=3,subBody=0\n")
dummy.write(
"WigleWifi-1.4,appRelease={},model=pwnagotchi,release={},device=pwnagotchi,display=kismet,board=kismet,brand=pwnagotchi\n".format(plugin_version, __pwnagotchi_version__))
dummy.write(
"MAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type")
"MAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type\n")
writer = csv.writer(dummy, delimiter=",", quoting=csv.QUOTE_NONE, escapechar="\\")
writer.writerow([
@ -64,7 +69,7 @@ def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
gps_data['Latitude'],
gps_data['Longitude'],
gps_data['Altitude'],
0, # accuracy?
gps_data['Accuracy'],
'WIFI'])
return dummy.getvalue()
@ -84,7 +89,7 @@ def _send_to_wigle(lines, api_key, donate=True, timeout=30):
headers = {'Authorization': f"Basic {api_key}",
'Accept': 'application/json'}
data = {'donate': 'on' if donate else 'false'}
payload = {'file': dummy, 'type': 'text/csv'}
payload = {'file': (pwnagotchi.name() + ".csv", dummy, 'multipart/form-data', {'Expires': '0'})}
try:
res = requests.post('https://api.wigle.net/api/v2/file/upload',
data=data,
@ -99,34 +104,32 @@ def _send_to_wigle(lines, api_key, donate=True, timeout=30):
class Wigle(plugins.Plugin):
__author__ = '33197631+dadav@users.noreply.github.com'
__version__ = '2.0.0'
__license__ = 'GPL3'
__description__ = 'This plugin automatically uploads collected wifis to wigle.net'
__author__ = "Dadav and updated by Jayofelony"
__version__ = "3.0.1"
__license__ = "GPL3"
__description__ = "This plugin automatically uploads collected WiFi to wigle.net"
def __init__(self):
self.ready = False
self.report = StatusFile('/root/.wigle_uploads', data_format='json')
self.skip = list()
self.lock = Lock()
self.options = dict()
def on_loaded(self):
if 'api_key' not in self.options or ('api_key' in self.options and self.options['api_key'] is None):
logging.debug("WIGLE: api_key isn't set. Can't upload to wigle.net")
return
if not 'whitelist' in self.options:
self.options['whitelist'] = list()
if not 'donate' in self.options:
self.options['donate'] = True
if 'donate' not in self.options:
self.options['donate'] = False
self.ready = True
logging.info("WIGLE: ready")
def on_internet_available(self, agent):
"""
Called in manual mode when there's internet connectivity
Called when there's internet connectivity
"""
if not self.ready or self.lock.locked():
return
@ -140,9 +143,9 @@ class Wigle(plugins.Plugin):
all_files = os.listdir(handshake_dir)
all_gps_files = [os.path.join(handshake_dir, filename)
for filename in all_files
if filename.endswith('.gps.json') or filename.endswith('.paw-gps.json') or filename.endswith('.geo.json')]
if filename.endswith('.gps.json') or filename.endswith('.geo.json')]
all_gps_files = remove_whitelisted(all_gps_files, self.options['whitelist'])
all_gps_files = remove_whitelisted(all_gps_files, config['main']['whitelist'])
new_gps_files = set(all_gps_files) - set(reported) - set(self.skip)
if new_gps_files:
logging.info("WIGLE: Internet connectivity detected. Uploading new handshakes to wigle.net")
@ -151,8 +154,6 @@ class Wigle(plugins.Plugin):
for gps_file in new_gps_files:
if gps_file.endswith('.gps.json'):
pcap_filename = gps_file.replace('.gps.json', '.pcap')
if gps_file.endswith('.paw-gps.json'):
pcap_filename = gps_file.replace('.paw-gps.json', '.pcap')
if gps_file.endswith('.geo.json'):
pcap_filename = gps_file.replace('.geo.json', '.pcap')
if not os.path.exists(pcap_filename):

View File

@ -76,9 +76,6 @@ class WpaSec(plugins.Plugin):
logging.error("WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured.")
return
if 'whitelist' not in self.options:
self.options['whitelist'] = list()
self.ready = True
logging.info("WPA_SEC: plugin loaded")
@ -101,9 +98,8 @@ class WpaSec(plugins.Plugin):
reported = self.report.data_field_or('reported', default=list())
handshake_dir = config['bettercap']['handshakes']
handshake_filenames = os.listdir(handshake_dir)
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if
filename.endswith('.pcap')]
handshake_paths = remove_whitelisted(handshake_paths, self.options['whitelist'])
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if filename.endswith('.pcap')]
handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist'])
handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
if handshake_new:

View File

@ -1 +0,0 @@

View File

@ -103,8 +103,8 @@ class Display(View):
def is_waveshare2in13d(self):
return self._implementation.name == 'waveshare2in13d'
def is_waveshare2in23g(self):
return self._implementation.name == 'waveshare2in23g'
def is_waveshare2in13g(self):
return self._implementation.name == 'waveshare2in13g'
def is_waveshare2in36g(self):
return self._implementation.name == 'waveshare2in36g'
@ -112,6 +112,9 @@ class Display(View):
def is_waveshare2in66(self):
return self._implementation.name == 'waveshare2in66'
def is_waveshare2in66b(self):
return self._implementation.name == 'waveshare2in66b'
def is_waveshare2in66g(self):
return self._implementation.name == 'waveshare2in66g'

View File

@ -16,50 +16,52 @@ from pwnagotchi.ui.hw.waveshare1in44lcd import Waveshare144lcd
from pwnagotchi.ui.hw.waveshare1in54b import Waveshare154inchb
from pwnagotchi.ui.hw.waveshare2in13bc import Waveshare213bc
from pwnagotchi.ui.hw.waveshare2in13d import Waveshare213d
from pwnagotchi.ui.hw.waveshare2in13g import Waveshare2in13g
from pwnagotchi.ui.hw.waveshare2in13b_V4 import Waveshare213bV4
from pwnagotchi.ui.hw.waveshare3in5lcd import Waveshare35lcd
from pwnagotchi.ui.hw.spotpear24in import Spotpear24inch
from pwnagotchi.ui.hw.displayhatmini import DisplayHatMini
# from pwnagotchi.ui.hw.waveshare1in02 import Waveshare102
from pwnagotchi.ui.hw.waveshare1in02 import Waveshare1in02
from pwnagotchi.ui.hw.waveshare1in54 import Waveshare154
from pwnagotchi.ui.hw.waveshare1in54_V2 import Waveshare154V2
from pwnagotchi.ui.hw.waveshare1in54b_V2 import Waveshare154bV2
# from pwnagotchi.ui.hw.waveshare1in54c import Waveshare154c
# from pwnagotchi.ui.hw.waveshare1in64g import Waveshare164g
from pwnagotchi.ui.hw.waveshare1in54c import Waveshare1in54c
from pwnagotchi.ui.hw.waveshare1in64g import Waveshare1in64g
from pwnagotchi.ui.hw.waveshare2in7b import Waveshare27b
from pwnagotchi.ui.hw.waveshare2in7b_V2 import Waveshare27bV2
from pwnagotchi.ui.hw.waveshare2in9b_V3 import Waveshare29bV3
from pwnagotchi.ui.hw.waveshare2in9b_V4 import Waveshare29bV4
# from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare29bc
# from pwnagotchi.ui.hw.waveshare2in9d import Waveshare29d
from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare213bV3
# from pwnagotchi.ui.hw.waveshare2in23g import Waveshare223g
# from pwnagotchi.ui.hw.waveshare2in36g import Waveshare236g
# from pwnagotchi.ui.hw.waveshare2in66 import Waveshare266
# from pwnagotchi.ui.hw.waveshare3in0g import Waveshare30g
# from pwnagotchi.ui.hw.waveshare3in7 import Waveshare37
# from pwnagotchi.ui.hw.waveshare3in52 import Waveshare352
# from pwnagotchi.ui.hw.waveshare4in01f import Waveshare401f
# from pwnagotchi.ui.hw.waveshare4in2 import Waveshare42inch
# from pwnagotchi.ui.hw.waveshare4in2_V2 import Waveshare42V2
# from pwnagotchi.ui.hw.waveshare4in2b_V2 import Waveshare42bV2
# from pwnagotchi.ui.hw.waveshare4in2bc import Waveshare42bc
# from pwnagotchi.ui.hw.waveshare4in26 import Waveshare426
# from pwnagotchi.ui.hw.waveshare4in37g import Waveshare437g
# from pwnagotchi.ui.hw.waveshare5in65f import Waveshare565f
# from pwnagotchi.ui.hw.waveshare5in83 import Waveshare583
# from pwnagotchi.ui.hw.waveshare5in83_V2 import Waveshare583V2
# from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare583bV2
# from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare583bc
# from pwnagotchi.ui.hw.waveshare7in3f import Waveshare73f
# from pwnagotchi.ui.hw.waveshare7in3g import Waveshare73g
# from pwnagotchi.ui.hw.waveshare7in5 import Waveshare75
# from pwnagotchi.ui.hw.waveshare7in5_HD import Waveshare75HD
# from pwnagotchi.ui.hw.waveshare7in5_V2 import Waveshare75V2
# from pwnagotchi.ui.hw.waveshare7in5b_HD import Waveshare75bHD
# from pwnagotchi.ui.hw.waveshare7in5b_V2 import Waveshare75bV2
# from pwnagotchi.ui.hw.waveshare7in5bc import Waveshare75bc
# from pwnagotchi.ui.hw.waveshare13in3k import Waveshare133k
from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare2in9bc
from pwnagotchi.ui.hw.waveshare2in9d import Waveshare2in9d
from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare2in13bV3
from pwnagotchi.ui.hw.waveshare2in36g import Waveshare2in36g
from pwnagotchi.ui.hw.waveshare2in66 import Waveshare2in66
from pwnagotchi.ui.hw.waveshare2in66b import Waveshare2in66b
from pwnagotchi.ui.hw.waveshare2in66g import Waveshare2in66g
from pwnagotchi.ui.hw.waveshare3in0g import Waveshare3in0g
from pwnagotchi.ui.hw.waveshare3in7 import Waveshare3in7
from pwnagotchi.ui.hw.waveshare3in52 import Waveshare3in52
from pwnagotchi.ui.hw.waveshare4in01f import Waveshare4in01f
from pwnagotchi.ui.hw.waveshare4in2 import Waveshare4in2
from pwnagotchi.ui.hw.waveshare4in2_V2 import Waveshare4in2V2
from pwnagotchi.ui.hw.waveshare4in2b_V2 import Waveshare4in2bV2
from pwnagotchi.ui.hw.waveshare4in2bc import Waveshare4in2bc
from pwnagotchi.ui.hw.waveshare4in26 import Waveshare4in26
from pwnagotchi.ui.hw.waveshare4in37g import Waveshare4in37g
from pwnagotchi.ui.hw.waveshare5in65f import Waveshare5in65f
from pwnagotchi.ui.hw.waveshare5in83 import Waveshare5in83
from pwnagotchi.ui.hw.waveshare5in83_V2 import Waveshare5in83V2
from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare5in83bV2
from pwnagotchi.ui.hw.waveshare5in83bc import Waveshare5in83bc
from pwnagotchi.ui.hw.waveshare7in3f import Waveshare7in3f
from pwnagotchi.ui.hw.waveshare7in3g import Waveshare7in3g
from pwnagotchi.ui.hw.waveshare7in5 import Waveshare7in5
from pwnagotchi.ui.hw.waveshare7in5_HD import Waveshare7in5HD
from pwnagotchi.ui.hw.waveshare7in5_V2 import Waveshare7in5V2
from pwnagotchi.ui.hw.waveshare7in5b_HD import Waveshare7in5bHD
from pwnagotchi.ui.hw.waveshare7in5b_V2 import Waveshare7in5bV2
from pwnagotchi.ui.hw.waveshare7in5bc import Waveshare7in5bc
from pwnagotchi.ui.hw.waveshare13in3k import Waveshare13in3k
def display_for(config):
@ -82,6 +84,21 @@ def display_for(config):
elif config['ui']['display']['type'] == 'dfrobot_2':
return DFRobotV2(config)
elif config['ui']['display']['type'] == 'waveshare144lcd':
return Waveshare144lcd(config)
elif config['ui']['display']['type'] == 'waveshare35lcd':
return Waveshare35lcd(config)
elif config['ui']['display']['type'] == 'spotpear24inch':
return Spotpear24inch(config)
elif config['ui']['display']['type'] == 'displayhatmini':
return DisplayHatMini(config)
elif config['ui']['display']['type'] == 'waveshare1in02':
return Waveshare1in02(config)
elif config['ui']['display']['type'] == 'waveshare1in54':
return Waveshare154(config)
@ -94,12 +111,36 @@ def display_for(config):
elif config['ui']['display']['type'] == 'waveshare1in54b_v2':
return Waveshare154bV2(config)
elif config['ui']['display']['type'] == 'waveshare1in54c':
return Waveshare1in54c(config)
elif config['ui']['display']['type'] == 'waveshare1in64g':
return Waveshare1in64g(config)
elif config['ui']['display']['type'] == 'waveshare2in7':
return Waveshare27inch(config)
elif config['ui']['display']['type'] == 'waveshare2in7_v2':
return Waveshare27inchV2(config)
elif config['ui']['display']['type'] == 'waveshare2in7b':
return Waveshare27b(config)
elif config['ui']['display']['type'] == 'waveshare2in7b_v2':
return Waveshare27bV2(config)
elif config['ui']['display']['type'] == 'waveshare2in9':
return Waveshare29inch(config)
elif config['ui']['display']['type'] == 'waveshare2in9bc':
return Waveshare2in9bc(config)
elif config['ui']['display']['type'] == 'waveshare2in9d':
return Waveshare2in9d(config)
elif config['ui']['display']['type'] == 'waveshare2in9_v2':
return Waveshare29inchV2(config)
elif config['ui']['display']['type'] == 'waveshare2in9b_v3':
return Waveshare29bV3(config)
@ -118,137 +159,101 @@ def display_for(config):
elif config['ui']['display']['type'] == 'waveshare_4':
return WaveshareV4(config)
elif config['ui']['display']['type'] == 'waveshare2in7':
return Waveshare27inch(config)
elif config['ui']['display']['type'] == 'waveshare2in7_v2':
return Waveshare27inchV2(config)
elif config['ui']['display']['type'] == 'waveshare2in9':
return Waveshare29inch(config)
elif config['ui']['display']['type'] == 'waveshare2in9_v2':
return Waveshare29inchV2(config)
elif config['ui']['display']['type'] == 'waveshare144lcd':
return Waveshare144lcd(config)
elif config['ui']['display']['type'] == 'waveshare1in54b':
return Waveshare154inchb(config)
elif config['ui']['display']['type'] == 'waveshare2in13bc':
return Waveshare213bc(config)
elif config['ui']['display']['type'] == 'waveshare2in13d':
return Waveshare213d(config)
elif config['ui']['display']['type'] == 'waveshare2in13b_v3':
return Waveshare2in13bV3(config)
elif config['ui']['display']['type'] == 'waveshare2in13b_v4':
return Waveshare213bV4(config)
elif config['ui']['display']['type'] == 'waveshare35lcd':
return Waveshare35lcd(config)
elif config['ui']['display']['type'] == 'spotpear24inch':
return Spotpear24inch(config)
elif config['ui']['display']['type'] == 'displayhatmini':
return DisplayHatMini(config)
elif config['ui']['display']['type'] == 'waveshare1in54c':
return
elif config['ui']['display']['type'] == 'waveshare1in64g':
return
elif config['ui']['display']['type'] == 'waveshare1in02':
return
elif config['ui']['display']['type'] == 'waveshare2in9bc':
return
elif config['ui']['display']['type'] == 'waveshare2in9d':
return
elif config['ui']['display']['type'] == 'waveshare2in13b_v3':
return
elif config['ui']['display']['type'] == 'waveshare2in23g':
return
elif config['ui']['display']['type'] == 'waveshare2in13g':
return Waveshare2in13g(config)
elif config['ui']['display']['type'] == 'waveshare2in36g':
return
return Waveshare2in36g(config)
elif config['ui']['display']['type'] == 'waveshare2in66':
return
return Waveshare2in66(config)
elif config['ui']['display']['type'] == 'waveshare2in66b':
return Waveshare2in66b(config)
elif config['ui']['display']['type'] == 'waveshare2in66g':
return Waveshare2in66g(config)
elif config['ui']['display']['type'] == 'waveshare3in0g':
return
return Waveshare3in0g(config)
elif config['ui']['display']['type'] == 'waveshare3in7':
return
return Waveshare3in7(config)
elif config['ui']['display']['type'] == 'waveshare3in52':
return
return Waveshare3in52(config)
elif config['ui']['display']['type'] == 'waveshare4in01f':
return
return Waveshare4in01f(config)
elif config['ui']['display']['type'] == 'waveshare4in2':
return
return Waveshare4in2(config)
elif config['ui']['display']['type'] == 'waveshare4in2_v2':
return
return Waveshare4in2V2(config)
elif config['ui']['display']['type'] == 'waveshare4in2b_v2':
return
return Waveshare4in2bV2(config)
elif config['ui']['display']['type'] == 'waveshare4in2bc':
return
return Waveshare4in2bc(config)
elif config['ui']['display']['type'] == 'waveshare4in26':
return
return Waveshare4in26(config)
elif config['ui']['display']['type'] == 'waveshare4in37g':
return
return Waveshare4in37g(config)
elif config['ui']['display']['type'] == 'waveshare5in65f':
return
return Waveshare5in65f(config)
elif config['ui']['display']['type'] == 'waveshare5in83':
return
return Waveshare5in83(config)
elif config['ui']['display']['type'] == 'waveshare5in83_v2':
return
return Waveshare5in83V2(config)
elif config['ui']['display']['type'] == 'waveshare5in83b_v2':
return
return Waveshare5in83bV2(config)
elif config['ui']['display']['type'] == 'waveshare5in83bc':
return
return Waveshare5in83bc(config)
elif config['ui']['display']['type'] == 'waveshare7in3f':
return
return Waveshare7in3f(config)
elif config['ui']['display']['type'] == 'waveshare7in3g':
return
return Waveshare7in3g(config)
elif config['ui']['display']['type'] == 'waveshare7in5':
return
return Waveshare7in5(config)
elif config['ui']['display']['type'] == 'waveshare7in5_HD':
return
return Waveshare7in5HD(config)
elif config['ui']['display']['type'] == 'waveshare7in5_v2':
return
return Waveshare7in5V2(config)
elif config['ui']['display']['type'] == 'waveshare7in5b_HD':
return
return Waveshare7in5bHD(config)
elif config['ui']['display']['type'] == 'waveshare7in5b_v2':
return
return Waveshare7in5bV2(config)
elif config['ui']['display']['type'] == 'waveshare7in5bc':
return
return Waveshare7in5bc(config)
elif config['ui']['display']['type'] == 'waveshare13in3k':
return
return Waveshare13in3k(config)

View File

@ -3,6 +3,7 @@ import pwnagotchi.ui.fonts as fonts
class DisplayImpl(object):
def __init__(self, config, name):
self._display = None
if fonts.Medium is None:
fonts.init(config)
self.name = name

View File

@ -3,41 +3,41 @@ import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class DFRobotV1(DisplayImpl):
def __init__(self, config):
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
self._display = None
def __init__(self, config):
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing dfrobot1 display")
from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot
self._display = DFRobot()
def initialize(self):
logging.info("initializing dfrobot1 display")
from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot
self._display = DFRobot()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def clear(self):
self._display.Clear(0xFF)
def clear(self):
self._display.Clear(0xFF)

View File

@ -3,41 +3,41 @@ import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class DFRobotV1(DisplayImpl):
def __init__(self, config):
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
self._display = None
def __init__(self, config):
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing dfrobot1 display")
from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot
self._display = DFRobot()
def initialize(self):
logging.info("initializing dfrobot1 display")
from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot
self._display = DFRobot()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def clear(self):
self._display.Clear(0xFF)
def clear(self):
self._display.Clear(0xFF)

View File

@ -3,41 +3,41 @@ import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class DFRobotV2(DisplayImpl):
def __init__(self, config):
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
self._display = None
def __init__(self, config):
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing dfrobot2 display")
from pwnagotchi.ui.hw.libs.dfrobot.v2.dfrobot import DFRobot
self._display = DFRobot()
def initialize(self):
logging.info("initializing dfrobot2 display")
from pwnagotchi.ui.hw.libs.dfrobot.v2.dfrobot import DFRobot
self._display = DFRobot()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def clear(self):
self._display.Clear(0xFF)
def clear(self):
self._display.Clear(0xFF)

View File

@ -3,41 +3,41 @@ import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class DFRobotV2(DisplayImpl):
def __init__(self, config):
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
self._display = None
def __init__(self, config):
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing dfrobot2 display")
from pwnagotchi.ui.hw.libs.dfrobot.v2.dfrobot import DFRobot
self._display = DFRobot()
def initialize(self):
logging.info("initializing dfrobot2 display")
from pwnagotchi.ui.hw.libs.dfrobot.v2.dfrobot import DFRobot
self._display = DFRobot()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def clear(self):
self._display.Clear(0xFF)
def clear(self):
self._display.Clear(0xFF)

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class DisplayHatMini(DisplayImpl):
def __init__(self, config):
super(DisplayHatMini, self).__init__(config, 'displayhatmini')
self._display = None
def layout(self):
fonts.setup(12, 10, 12, 70, 25, 9)

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Inky(DisplayImpl):
def __init__(self, config):
super(Inky, self).__init__(config, 'inky')
self._display = None
def layout(self):
fonts.setup(10, 8, 10, 28, 25, 9)

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class LcdHat(DisplayImpl):
def __init__(self, config):
super(LcdHat, self).__init__(config, 'lcdhat')
self._display = None
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)

View File

@ -12,6 +12,7 @@ from . import config
from . import LCD_1in44
from PIL import ImageOps
class EPD(object):
def __init__(self):
self.width = 128
@ -24,9 +25,8 @@ class EPD(object):
pass
def clear(self):
#self.LCD.LCD_Clear()
pass
self.LCD.LCD_Clear()
def display(self, image):
rgb_im = ImageOps.colorize(image.convert("L"), black ="green", white ="black")
rgb_im = ImageOps.colorize(image.convert("L"), black="green", white="black")
self.LCD.LCD_ShowImage(rgb_im, 0, 0)

View File

@ -2,11 +2,12 @@ from . import SH1106
from . import config
# Display resolution
EPD_WIDTH = 64
EPD_HEIGHT = 128
EPD_WIDTH = 64
EPD_HEIGHT = 128
disp = SH1106.SH1106()
class EPD(object):
def __init__(self):

View File

@ -1,219 +0,0 @@
# *****************************************************************************
# * | File : epd1in54b.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 = 200
EPD_HEIGHT = 200
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
lut_vcom0 = [0x0E, 0x14, 0x01, 0x0A, 0x06, 0x04, 0x0A, 0x0A, 0x0F, 0x03, 0x03, 0x0C, 0x06, 0x0A, 0x00]
lut_w = [0x0E, 0x14, 0x01, 0x0A, 0x46, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x86, 0x0A, 0x04]
lut_b = [0x0E, 0x14, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x4A, 0x04]
lut_g1 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04]
lut_g2 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04]
lut_vcom1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
lut_red0 = [0x83, 0x5D, 0x01, 0x81, 0x48, 0x23, 0x77, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
lut_red1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0) # module reset
epdconfig.delay_ms(10)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
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 ReadBusy(self):
logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0):
epdconfig.delay_ms(100)
logging.debug("e-Paper busy release")
def set_lut_bw(self):
self.send_command(0x20) # vcom
for count in range(0, 15):
self.send_data(self.lut_vcom0[count])
self.send_command(0x21) # ww --
for count in range(0, 15):
self.send_data(self.lut_w[count])
self.send_command(0x22) # bw r
for count in range(0, 15):
self.send_data(self.lut_b[count])
self.send_command(0x23) # wb w
for count in range(0, 15):
self.send_data(self.lut_g1[count])
self.send_command(0x24) # bb b
for count in range(0, 15):
self.send_data(self.lut_g2[count])
def set_lut_red(self):
self.send_command(0x25)
for count in range(0, 15):
self.send_data(self.lut_vcom1[count])
self.send_command(0x26)
for count in range(0, 15):
self.send_data(self.lut_red0[count])
self.send_command(0x27)
for count in range(0, 15):
self.send_data(self.lut_red1[count])
def init(self):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.send_command(0x01) # POWER_SETTING
self.send_data(0x07)
self.send_data(0x00)
self.send_data(0x08)
self.send_data(0x00)
self.send_command(0x06) # BOOSTER_SOFT_START
self.send_data(0x07)
self.send_data(0x07)
self.send_data(0x07)
self.send_command(0x04) # POWER_ON
self.ReadBusy()
self.send_command(0X00) # PANEL_SETTING
self.send_data(0xCF)
self.send_command(0X50) # VCOM_AND_DATA_INTERVAL_SETTING
self.send_data(0x17)
self.send_command(0x30) # PLL_CONTROL
self.send_data(0x39)
self.send_command(0x61) # TCON_RESOLUTION set x and y
self.send_data(0xC8)
self.send_data(0x00)
self.send_data(0xC8)
self.send_command(0x82) # VCM_DC_SETTING_REGISTER
self.send_data(0x0E)
self.set_lut_bw()
self.set_lut_red()
return 0
def getbuffer(self, image):
buf = [0xFF] * int(self.width * self.height / 8)
# Set buffer to value of Python Imaging Library image.
# Image must be in mode 1.
image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size
if imwidth != self.width or imheight != self.height:
raise ValueError('Image must be same dimensions as display \
({0}x{1}).' .format(self.width, self.height))
pixels = image_monocolor.load()
for y in range(self.height):
for x in range(self.width):
# 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))
return buf
def display(self, blackimage, redimage):
# send black data
if (blackimage != None):
self.send_command(0x10) # DATA_START_TRANSMISSION_1
for i in range(0, int(self.width * self.height / 8)):
temp = 0x00
for bit in range(0, 4):
if (blackimage[i] & (0x80 >> bit) != 0):
temp |= 0xC0 >> (bit * 2)
self.send_data(temp)
temp = 0x00
for bit in range(4, 8):
if (blackimage[i] & (0x80 >> bit) != 0):
temp |= 0xC0 >> ((bit - 4) * 2)
self.send_data(temp)
# send red data
if (redimage != None):
self.send_command(0x13) # DATA_START_TRANSMISSION_2
for i in range(0, int(self.width * self.height / 8)):
self.send_data(redimage[i])
self.send_command(0x12) # DISPLAY_REFRESH
self.ReadBusy()
def Clear(self):
self.send_command(0x10) # DATA_START_TRANSMISSION_1
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
self.send_data(0xFF)
self.send_command(0x13) # DATA_START_TRANSMISSION_2
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
self.send_command(0x12) # DISPLAY_REFRESH
self.ReadBusy()
def sleep(self):
self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING
self.send_data(0x17)
self.send_command(0x82) # to solve Vcom drop
self.send_data(0x00)
self.send_command(0x01) # power setting
self.send_data(0x02) # gate switch to external
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.ReadBusy()
self.send_command(0x02) # power off
epdconfig.module_exit()
### END OF FILE ###

View File

@ -1,154 +0,0 @@
# /*****************************************************************************
# * | File : epdconfig.py
# * | Author : Waveshare team
# * | Function : Hardware underlying interface
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-06-21
# * | 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
class RaspberryPi:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
def __init__(self):
import spidev
import RPi.GPIO
self.GPIO = RPi.GPIO
# SPI device, bus = 0, device = 0
self.SPI = spidev.SpiDev(0, 0)
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.max_speed_hz = 4000000
self.SPI.mode = 0b00
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.close()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
class JetsonNano:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.SYSFS_software_spi_begin()
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.SYSFS_software_spi_end()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
implementation = RaspberryPi()
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 ###

View File

@ -264,11 +264,11 @@ class EPD:
def display(self, image):
if (image == None):
return
# Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1)
# Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1)
if (self.width % 8 == 0):
Width = self.width / 8
Width = self.width // 8
else:
Width = self.width / 8 + 1
Width = self.width // 8 + 1
self.send_command(0x10)
for j in range(0, self.height):
@ -282,11 +282,11 @@ class EPD:
self.TurnOnDisplay()
def Clear(self):
# Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1)
# Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1)
if (self.width % 8 == 0):
Width = self.width / 8
Width = self.width // 8
else:
Width = self.width / 8 + 1
Width = self.width // 8 + 1
Height = self.height
@ -313,11 +313,11 @@ class EPD:
self.send_data(127) # y-end
self.send_data(0x00)
# Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1)
# Width = (self.width % 8 == 0)? (self.width // 8 ): (self.width // 8 + 1)
if (self.width % 8 == 0):
Width = self.width / 8
Width = self.width // 8
else:
Width = self.width / 8 + 1
Width = self.width // 8 + 1
Height = self.height
# send data

View File

@ -169,7 +169,7 @@ class EPD:
# self.ReadBusy()
def init(self, lut):
if (epdconfig.module_init() != 0):
if epdconfig.module_init() != 0:
return -1
# EPD hardware init start
self.reset()

View File

@ -1,378 +0,0 @@
# *****************************************************************************
# * | File : epd2in13bc.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
from PIL import Image
# Display resolution
EPD_WIDTH = 104
EPD_HEIGHT = 212
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
lut_vcomDC = [
0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
0x60, 0x28, 0x28, 0x00, 0x00, 0x01,
0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
]
lut_ww = [
0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_bw = [
0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x0F, 0x0F, 0x00, 0x00, 0x03,
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01,
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_wb = [
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_bb = [
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_vcom1 = [
0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_ww1 = [
0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_bw1 = [
0x80, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_wb1 = [
0x40, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_bb1 = [
0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(10)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
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 ReadBusy(self):
logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100)
logging.debug("e-Paper busy release")
def TurnOnDisplay(self):
self.send_command(0x12)
epdconfig.delay_ms(10)
self.ReadBusy()
def init(self):
if (epdconfig.module_init() != 0):
return -1
logging.debug("e-Paper 2.13bc preboot Freeze recovery")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100)
self.reset()
epdconfig.delay_ms(200)
self.send_command(0x01) # POWER SETTING
self.send_data(0x03)
self.send_data(0x00)
self.send_data(0x2b)
self.send_data(0x2b)
self.send_data(0x03)
epdconfig.delay_ms(200)
self.send_command(0x06) # BOOSTER_SOFT_START
self.send_data(0x17)
self.send_data(0x17)
self.send_data(0x17)
self.send_command(0x04) # POWER_ON
epdconfig.delay_ms(200)
self.send_command(0X50)
self.send_data(0xf7)
self.send_command(0X02) # power off
self.send_command(0X07) # deep sleep
self.send_data(0xA5)
epdconfig.GPIO.output(epdconfig.RST_PIN, 0)
epdconfig.GPIO.output(epdconfig.DC_PIN, 0)
epdconfig.GPIO.output(epdconfig.CS_PIN, 0)
#logging.debug("Reset, powerdown, voltage off done")
logging.debug("e-Paper is not frozen now :)")
self.reset()
self.send_command(0x01) # POWER SETTING
self.send_data(0x03)
self.send_data(0x00)
self.send_data(0x2b)
self.send_data(0x2b)
self.send_data(0x03)
self.send_command(0x06) # BOOSTER_SOFT_START
self.send_data(0x17)
self.send_data(0x17)
self.send_data(0x17)
self.send_command(0x04) # POWER_ON
logging.debug("e-Paper 2.13bc bootup busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100)
# self.send_command(0x00) # PANEL_SETTING
# self.send_data(0x8F)
# self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING
# self.send_data(0xF0)
# self.send_command(0x61) # RESOLUTION_SETTING
# self.send_data(self.width & 0xff)
# self.send_data(self.height >> 8)
# self.send_data(self.height & 0xff)
self.send_command(0x00) # panel setting
self.send_data(0xbf) # LUT from OTP,128x296
self.send_data(0x0d) # VCOM to 0V fast
self.send_command(0x30) # PLL setting
self.send_data(0x3a) # 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
self.send_command(0x61) # resolution setting
self.send_data(self.width & 0xff)
self.send_data((self.height >> 8) & 0xff)
self.send_data(self.height& 0xff)
self.send_command(0x82) # vcom_DC setting
self.send_data(0x28)
#self.Clear()
logging.debug("e-Paper booted")
return 0
def SetFullReg(self):
self.send_command(0x82)
self.send_data(0x00)
self.send_command(0X50)
self.send_data(0x97)
self.send_command(0x20) # vcom
for count in range(0, 44):
self.send_data(self.lut_vcomDC[count])
self.send_command(0x21) # ww --
for count in range(0, 42):
self.send_data(self.lut_ww[count])
self.send_command(0x22) # bw r
for count in range(0, 42):
self.send_data(self.lut_bw[count])
self.send_command(0x23) # wb w
for count in range(0, 42):
self.send_data(self.lut_wb[count])
self.send_command(0x24) # bb b
for count in range(0, 42):
self.send_data(self.lut_bb[count])
def getbuffer(self, image):
# logging.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()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height):
logging.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] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width):
logging.debug("Horizontal")
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, imageblack, imagered):
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(imageblack[i])
self.send_command(0x92)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(imagered[i])
self.send_command(0x92)
self.send_command(0x12) # REFRESH
self.ReadBusy()
def pwndisplay(self, imageblack):
if (Image == None):
return
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0x00)
epdconfig.delay_ms(10)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(imageblack[i])
epdconfig.delay_ms(10)
self.SetFullReg()
self.TurnOnDisplay()
def Clear(self):
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
self.send_command(0x92)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
self.send_command(0x92)
self.send_command(0x12) # REFRESH
self.ReadBusy()
def pwnclear(self):
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
epdconfig.delay_ms(10)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
epdconfig.delay_ms(10)
self.SetFullReg()
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x02) # POWER_OFF
self.ReadBusy()
self.send_command(0x07) # DEEP_SLEEP
self.send_data(0xA5) # check code
epdconfig.module_exit()
### END OF FILE ###

View File

@ -1,154 +0,0 @@
# /*****************************************************************************
# * | File : epdconfig.py
# * | Author : Waveshare team
# * | Function : Hardware underlying interface
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-06-21
# * | 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
class RaspberryPi:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
def __init__(self):
import spidev
import RPi.GPIO
self.GPIO = RPi.GPIO
# SPI device, bus = 0, device = 0
self.SPI = spidev.SpiDev(0, 0)
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.max_speed_hz = 4000000
self.SPI.mode = 0b00
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.close()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
class JetsonNano:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.SYSFS_software_spi_begin()
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.SYSFS_software_spi_end()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
implementation = RaspberryPi()
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 ###

View File

@ -1,358 +0,0 @@
# *****************************************************************************
# * | File : epd2in13d.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
from PIL import Image
import RPi.GPIO as GPIO
# Display resolution
EPD_WIDTH = 104
EPD_HEIGHT = 212
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
lut_vcomDC = [
0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
0x60, 0x28, 0x28, 0x00, 0x00, 0x01,
0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
]
lut_ww = [
0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_bw = [
0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x0F, 0x0F, 0x00, 0x00, 0x03,
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01,
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_wb = [
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_bb = [
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_vcom1 = [
0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_ww1 = [
0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_bw1 = [
0x80, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_wb1 = [
0x40, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
lut_bb1 = [
0x00, 0x19, 0x01, 0x00, 0x00, 0x01,
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,
]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(10)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
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 ReadBusy(self):
logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
self.send_command(0x71)
epdconfig.delay_ms(100)
logging.debug("e-Paper busy release")
def TurnOnDisplay(self):
self.send_command(0x12)
epdconfig.delay_ms(10)
self.ReadBusy()
def init(self):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.send_command(0x01) # POWER SETTING
self.send_data(0x03)
self.send_data(0x00)
self.send_data(0x2b)
self.send_data(0x2b)
self.send_data(0x03)
self.send_command(0x06) # boost soft start
self.send_data(0x17) # A
self.send_data(0x17) # B
self.send_data(0x17) # C
self.send_command(0x04)
self.ReadBusy()
self.send_command(0x00) # panel setting
self.send_data(0xbf) # LUT from OTP,128x296
self.send_data(0x0d) # VCOM to 0V fast
self.send_command(0x30) # PLL setting
self.send_data(0x3a) # 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
self.send_command(0x61) # resolution setting
self.send_data(self.width)
self.send_data((self.height >> 8) & 0xff)
self.send_data(self.height& 0xff)
self.send_command(0x82) # vcom_DC setting
self.send_data(0x28)
return 0
def SetFullReg(self):
self.send_command(0x82)
self.send_data(0x00)
self.send_command(0X50)
self.send_data(0x97)
self.send_command(0x20) # vcom
for count in range(0, 44):
self.send_data(self.lut_vcomDC[count])
self.send_command(0x21) # ww --
for count in range(0, 42):
self.send_data(self.lut_ww[count])
self.send_command(0x22) # bw r
for count in range(0, 42):
self.send_data(self.lut_bw[count])
self.send_command(0x23) # wb w
for count in range(0, 42):
self.send_data(self.lut_wb[count])
self.send_command(0x24) # bb b
for count in range(0, 42):
self.send_data(self.lut_bb[count])
def SetPartReg(self):
self.send_command(0x82)
self.send_data(0x03)
self.send_command(0X50)
self.send_data(0x47)
self.send_command(0x20) # vcom
for count in range(0, 44):
self.send_data(self.lut_vcom1[count])
self.send_command(0x21) # ww --
for count in range(0, 42):
self.send_data(self.lut_ww1[count])
self.send_command(0x22) # bw r
for count in range(0, 42):
self.send_data(self.lut_bw1[count])
self.send_command(0x23) # wb w
for count in range(0, 42):
self.send_data(self.lut_wb1[count])
self.send_command(0x24) # bb b
for count in range(0, 42):
self.send_data(self.lut_bb1[count])
def getbuffer(self, image):
# logging.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()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height):
logging.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] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width):
logging.debug("Horizontal")
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):
if (Image == None):
return
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0x00)
epdconfig.delay_ms(10)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(image[i])
epdconfig.delay_ms(10)
self.SetFullReg()
self.TurnOnDisplay()
def DisplayPartial(self, image):
if (Image == None):
return
self.SetPartReg()
self.send_command(0x91)
self.send_command(0x90)
self.send_data(0)
self.send_data(self.width - 1)
self.send_data(0)
self.send_data(0)
self.send_data(int(self.height / 256))
self.send_data(self.height % 256 - 1)
self.send_data(0x28)
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(image[i])
epdconfig.delay_ms(10)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(~image[i])
epdconfig.delay_ms(10)
self.TurnOnDisplay()
def Clear(self):
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0x00)
epdconfig.delay_ms(10)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
epdconfig.delay_ms(10)
self.SetFullReg()
self.TurnOnDisplay()
def sleep(self):
self.send_command(0X50)
self.send_data(0xf7)
self.send_command(0X02) # power off
self.send_command(0X07) # deep sleep
self.send_data(0xA5)
epdconfig.module_exit()
### END OF FILE ###

View File

@ -1,154 +0,0 @@
# /*****************************************************************************
# * | File : epdconfig.py
# * | Author : Waveshare team
# * | Function : Hardware underlying interface
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-06-21
# * | 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
class RaspberryPi:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
def __init__(self):
import spidev
import RPi.GPIO
self.GPIO = RPi.GPIO
# SPI device, bus = 0, device = 0
self.SPI = spidev.SpiDev(0, 0)
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.max_speed_hz = 4000000
self.SPI.mode = 0b00
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.close()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
class JetsonNano:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.SYSFS_software_spi_begin()
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.SYSFS_software_spi_end()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
implementation = RaspberryPi()
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 ###

View File

@ -1,227 +0,0 @@
# /*****************************************************************************
# * | 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
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.BUSY_PIN, self.GPIO.IN)
# 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.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN])
class JetsonNano:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
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.BUSY_PIN, self.GPIO.IN)
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.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN])
class SunriseX3:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
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.BUSY_PIN, self.GPIO.IN)
# 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.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_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 ###

View File

@ -1,520 +0,0 @@
# *****************************************************************************
# * | File : epd2in7.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 documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS 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 = 176
EPD_HEIGHT = 264
GRAY1 = 0xff #white
GRAY2 = 0xC0
GRAY3 = 0x80 #gray
GRAY4 = 0x00 #Blackest
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.GRAY1 = GRAY1 #white
self.GRAY2 = GRAY2
self.GRAY3 = GRAY3 #gray
self.GRAY4 = GRAY4 #Blackest
lut_vcom_dc = [0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
0x60, 0x28, 0x28, 0x00, 0x00, 0x01,
0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]
lut_ww = [
0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_bw = [
0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_bb = [
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
lut_wb = [
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
###################full screen update LUT######################
#0~3 gray
gray_lut_vcom = [
0x00, 0x00,
0x00, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x60, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00, 0x13, 0x0A, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
#R21
gray_lut_ww =[
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x10, 0x14, 0x0A, 0x00, 0x00, 0x01,
0xA0, 0x13, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
#R22H r
gray_lut_bw =[
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99, 0x0C, 0x01, 0x03, 0x04, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
#R23H w
gray_lut_wb =[
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99, 0x0B, 0x04, 0x04, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
#R24H b
gray_lut_bb =[
0x80, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x20, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x50, 0x13, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(10)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
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 ReadBusy(self):
logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(200)
logging.debug("e-Paper busy release")
def set_lut(self):
self.send_command(0x20) # vcom
for count in range(0, 44):
self.send_data(self.lut_vcom_dc[count])
self.send_command(0x21) # ww --
for count in range(0, 42):
self.send_data(self.lut_ww[count])
self.send_command(0x22) # bw r
for count in range(0, 42):
self.send_data(self.lut_bw[count])
self.send_command(0x23) # wb w
for count in range(0, 42):
self.send_data(self.lut_bb[count])
self.send_command(0x24) # bb b
for count in range(0, 42):
self.send_data(self.lut_wb[count])
def gray_SetLut(self):
self.send_command(0x20)
for count in range(0, 44): #vcom
self.send_data(self.gray_lut_vcom[count])
self.send_command(0x21) #red not use
for count in range(0, 42):
self.send_data(self.gray_lut_ww[count])
self.send_command(0x22) #bw r
for count in range(0, 42):
self.send_data(self.gray_lut_bw[count])
self.send_command(0x23) #wb w
for count in range(0, 42):
self.send_data(self.gray_lut_wb[count])
self.send_command(0x24) #bb b
for count in range(0, 42):
self.send_data(self.gray_lut_bb[count])
self.send_command(0x25) #vcom
for count in range(0, 42):
self.send_data(self.gray_lut_ww[count])
def init(self):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.send_command(0x01) # POWER_SETTING
self.send_data(0x03) # VDS_EN, VDG_EN
self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0]
self.send_data(0x2b) # VDH
self.send_data(0x2b) # VDL
self.send_data(0x09) # VDHR
self.send_command(0x06) # BOOSTER_SOFT_START
self.send_data(0x07)
self.send_data(0x07)
self.send_data(0x17)
# Power optimization
self.send_command(0xF8)
self.send_data(0x60)
self.send_data(0xA5)
# Power optimization
self.send_command(0xF8)
self.send_data(0x89)
self.send_data(0xA5)
# Power optimization
self.send_command(0xF8)
self.send_data(0x90)
self.send_data(0x00)
# Power optimization
self.send_command(0xF8)
self.send_data(0x93)
self.send_data(0x2A)
# Power optimization
self.send_command(0xF8)
self.send_data(0xA0)
self.send_data(0xA5)
# Power optimization
self.send_command(0xF8)
self.send_data(0xA1)
self.send_data(0x00)
# Power optimization
self.send_command(0xF8)
self.send_data(0x73)
self.send_data(0x41)
self.send_command(0x16) # PARTIAL_DISPLAY_REFRESH
self.send_data(0x00)
self.send_command(0x04) # POWER_ON
self.ReadBusy()
self.send_command(0x00) # PANEL_SETTING
self.send_data(0xAF) # KW-BF KWR-AF BWROTP 0f
self.send_command(0x30) # PLL_CONTROL
self.send_data(0x3A) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
self.send_command(0x82) # VCM_DC_SETTING_REGISTER
self.send_data(0x12)
self.set_lut()
return 0
def Init_4Gray(self):
if (epdconfig.module_init() != 0):
return -1
self.reset()
self.send_command(0x01) #POWER SETTING
self.send_data (0x03)
self.send_data (0x00)
self.send_data (0x2b)
self.send_data (0x2b)
self.send_command(0x06) #booster soft start
self.send_data (0x07) #A
self.send_data (0x07) #B
self.send_data (0x17) #C
self.send_command(0xF8) #boost??
self.send_data (0x60)
self.send_data (0xA5)
self.send_command(0xF8) #boost??
self.send_data (0x89)
self.send_data (0xA5)
self.send_command(0xF8) #boost??
self.send_data (0x90)
self.send_data (0x00)
self.send_command(0xF8) #boost??
self.send_data (0x93)
self.send_data (0x2A)
self.send_command(0xF8) #boost??
self.send_data (0xa0)
self.send_data (0xa5)
self.send_command(0xF8) #boost??
self.send_data (0xa1)
self.send_data (0x00)
self.send_command(0xF8) #boost??
self.send_data (0x73)
self.send_data (0x41)
self.send_command(0x16)
self.send_data(0x00)
self.send_command(0x04)
self.ReadBusy()
self.send_command(0x00) #panel setting
self.send_data(0xbf) #KW-BF KWR-AF BWROTP 0f
self.send_command(0x30) #PLL setting
self.send_data (0x90) #100hz
self.send_command(0x61) #resolution setting
self.send_data (0x00) #176
self.send_data (0xb0)
self.send_data (0x01) #264
self.send_data (0x08)
self.send_command(0x82) #vcom_DC setting
self.send_data (0x12)
self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING
self.send_data(0x97)
def getbuffer(self, image):
# logging.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()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height):
logging.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] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width):
logging.debug("Horizontal")
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):
# logging.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
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height):
logging.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):
logging.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 display(self, image):
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(image[i])
self.send_command(0x12)
self.ReadBusy()
def display_4Gray(self, image):
self.send_command(0x10)
for i in range(0, 5808): #5808*4 46464
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
self.send_data(temp3)
self.send_command(0x13)
for i in range(0, 5808): #5808*4 46464
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
self.send_data(temp3)
self.gray_SetLut()
self.send_command(0x12)
epdconfig.delay_ms(200)
self.ReadBusy()
# pass
def Clear(self, color):
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
self.send_command(0x13)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)
self.send_command(0x12)
self.ReadBusy()
def sleep(self):
self.send_command(0X50)
self.send_data(0xf7)
self.send_command(0X02)
self.send_command(0X07)
self.send_data(0xA5)
epdconfig.module_exit()
### END OF FILE ###

View File

@ -1,154 +0,0 @@
# /*****************************************************************************
# * | File : epdconfig.py
# * | Author : Waveshare team
# * | Function : Hardware underlying interface
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-06-21
# * | Info :
# ******************************************************************************
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS 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
class RaspberryPi:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
def __init__(self):
import spidev
import RPi.GPIO
self.GPIO = RPi.GPIO
# SPI device, bus = 0, device = 0
self.SPI = spidev.SpiDev(0, 0)
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.max_speed_hz = 4000000
self.SPI.mode = 0b00
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.close()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
class JetsonNano:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.SYSFS_software_spi_begin()
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.SYSFS_software_spi_end()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
implementation = RaspberryPi()
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 ###

View File

@ -1,520 +0,0 @@
# *****************************************************************************
# * | File : epd2in7_V2.py
# * | Author : Waveshare team
# * | Function : Electronic paper driver
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2022-09-17
# # | 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 = 176
EPD_HEIGHT = 264
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.GRAY1 = GRAY1 # white
self.GRAY2 = GRAY2
self.GRAY3 = GRAY3 # gray
self.GRAY4 = GRAY4 # Blackest
LUT_DATA_4Gray = [
0x40, 0x48, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x8, 0x48, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x2, 0x48, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x20, 0x48, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xA, 0x19, 0x0, 0x3, 0x8, 0x0, 0x0,
0x14, 0x1, 0x0, 0x14, 0x1, 0x0, 0x3,
0xA, 0x3, 0x0, 0x8, 0x19, 0x0, 0x0,
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
0x22, 0x17, 0x41, 0x0, 0x32, 0x1C,
]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(2)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
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 ReadBusy(self):
logger.debug("e-Paper busy")
while (epdconfig.digital_read(self.busy_pin) == 1): # 1: idle, 0: 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(0xC7)
self.send_command(0x20) # Activate Display Update Sequence
self.ReadBusy()
def Lut(self):
self.send_command(0x32)
for i in range(159):
self.send_data(self.LUT_DATA_4Gray[i])
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(0x45) # set Ram-Y address start/end position
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x07) # 0x0107-->(263+1)=264
self.send_data(0x01)
self.send_command(0x4F) # set RAM y address count to 0;
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x11) # data entry mode
self.send_data(0x03)
return 0
def init_Fast(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(0x12) # SWRESET
self.ReadBusy()
self.send_command(0x18) # Read built-in temperature sensor
self.send_data(0x80)
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(0x45) # set Ram-Y address start/end position
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x07) # 0x0107-->(263+1)=264
self.send_data(0x01)
self.send_command(0x4F) # set RAM y address count to 0;
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x11) # data entry mode
self.send_data(0x03)
self.send_command(0x22) # Load temperature value
self.send_data(0x91)
self.send_command(0x20)
self.ReadBusy()
return 0
def Init_4Gray(self):
if (epdconfig.module_init() != 0):
return -1
self.reset()
self.send_command(0x12) # soft reset
self.ReadBusy();
self.send_command(0x74) # set analog block control
self.send_data(0x54)
self.send_command(0x7E) # set digital block control
self.send_data(0x3B)
self.send_command(0x01) # Driver output control
self.send_data(0x07)
self.send_data(0x01)
self.send_data(0x00)
self.send_command(0x11) # data entry mode
self.send_data(0x03)
self.send_command(0x44) # set Ram-X address start/end position
self.send_data(0x00)
self.send_data(0x15) # 0x15-->(21+1)*8=176
self.send_command(0x45) # set Ram-Y address start/end position
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x07) # 0x0107-->(263+1)=264
self.send_data(0x01)
self.send_command(0x3C) # BorderWavefrom
self.send_data(0x00)
self.send_command(0x2C) # VCOM Voltage
self.send_data(self.LUT_DATA_4Gray[158]) # 0x1C
self.send_command(0x3F) # EOPQ
self.send_data(self.LUT_DATA_4Gray[153])
self.send_command(0x03) # VGH
self.send_data(self.LUT_DATA_4Gray[154])
self.send_command(0x04) #
self.send_data(self.LUT_DATA_4Gray[155]) # VSH1
self.send_data(self.LUT_DATA_4Gray[156]) # VSH2
self.send_data(self.LUT_DATA_4Gray[157]) # VSL
self.Lut() # LUT
self.send_command(0x4E) # set RAM x address count to 0;
self.send_data(0x00)
self.send_command(0x4F) # set RAM y address count to 0X199;
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("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] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif (imwidth == self.height and imheight == self.width):
logger.debug("Horizontal")
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 = 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 Clear(self):
if (self.width % 8 == 0):
Width = self.width // 8
else:
Width = self.width // 8 + 1
Height = self.height
self.send_command(0x24)
for j in range(Height):
for i in range(Width):
self.send_data(0XFF)
self.TurnOnDisplay()
def display(self, image):
if (self.width % 8 == 0):
Width = self.width // 8
else:
Width = self.width // 8 + 1
Height = self.height
self.send_command(0x24)
for j in range(Height):
for i in range(Width):
self.send_data(image[i + j * Width])
self.TurnOnDisplay()
def display_Fast(self, image):
if (self.width % 8 == 0):
Width = self.width // 8
else:
Width = self.width // 8 + 1
Height = self.height
self.send_command(0x24)
for j in range(Height):
for i in range(Width):
self.send_data(image[i + j * Width])
self.TurnOnDisplay_Fast()
def display_Base(self, image):
if (self.width % 8 == 0):
Width = self.width // 8
else:
Width = self.width // 8 + 1
Height = self.height
self.send_command(0x24) # Write Black and White image to RAM
for j in range(Height):
for i in range(Width):
self.send_data(image[i + j * Width])
self.send_command(0x26) # Write Black and White image to RAM
for j in range(Height):
for i in range(Width):
self.send_data(image[i + j * Width])
self.TurnOnDisplay()
def display_Base_color(self, color):
if (self.width % 8 == 0):
Width = self.width // 8
else:
Width = self.width // 8 + 1
Height = self.height
self.send_command(0x24) # Write Black and White image to RAM
for j in range(Height):
for i in range(Width):
self.send_data(color)
self.send_command(0x26) # Write Black and White image to RAM
for j in range(Height):
for i in range(Width):
self.send_data(color)
# self.TurnOnDisplay()
def display_Partial(self, Image, Xstart, Ystart, Xend, Yend):
if ((Xstart % 8 + Xend % 8 == 8 & Xstart % 8 > Xend % 8) | Xstart % 8 + Xend % 8 == 0 | (
Xend - Xstart) % 8 == 0):
Xstart = Xstart // 8
Xend = Xend // 8
else:
Xstart = Xstart // 8
if Xend % 8 == 0:
Xend = Xend // 8
else:
Xend = Xend // 8 + 1
if (self.width % 8 == 0):
Width = self.width // 8
else:
Width = self.width // 8 + 1
Height = self.height
Xend -= 1
Yend -= 1
# Reset
self.reset()
self.send_command(0x3C) # BorderWavefrom
self.send_data(0x80)
self.send_command(0x44) # set RAM x address start/end, in page 35
self.send_data(Xstart & 0xff) # RAM x address start at 00h;
self.send_data(Xend & 0xff) # RAM x address end at 0fh(15+1)*8->128
self.send_command(0x45) # set RAM y address start/end, in page 35
self.send_data(Ystart & 0xff) # RAM y address start at 0127h;
self.send_data((Ystart >> 8) & 0x01) # RAM y address start at 0127h;
self.send_data(Yend & 0xff) # RAM y address end at 00h;
self.send_data((Yend >> 8) & 0x01)
self.send_command(0x4E) # set RAM x address count to 0;
self.send_data(Xstart & 0xff)
self.send_command(0x4F) # set RAM y address count to 0X127;
self.send_data(Ystart & 0xff)
self.send_data((Ystart >> 8) & 0x01)
self.send_command(0x24) # Write Black and White image to RAM
for j in range(Height):
for i in range(Width):
if ((j > Ystart - 1) & (j < (Yend + 1)) & (i > Xstart - 1) & (i < (Xend + 1))):
self.send_data(Image[i + j * Width])
self.TurnOnDisplay_Partial()
def display_4Gray(self, image):
self.send_command(0x24)
for i in range(0, 5808): # 5808*4 46464
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, 5808): # 5808*4 46464
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_4GRAY()
def sleep(self):
self.send_command(0X10)
self.send_data(0x01)
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###

View File

@ -1,243 +0,0 @@
# /*****************************************************************************
# * | 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 ###

View File

@ -1,201 +0,0 @@
# *****************************************************************************
# * | File : epd2in9.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 = 128
EPD_HEIGHT = 296
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
lut_full_update = [
0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]
lut_partial_update = [
0x10, 0x18, 0x18, 0x08, 0x18, 0x18,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(10)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
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 ReadBusy(self):
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(200)
def TurnOnDisplay(self):
self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2
self.send_data(0xC4)
self.send_command(0x20) # MASTER_ACTIVATION
self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE
logging.debug("e-Paper busy")
self.ReadBusy()
logging.debug("e-Paper busy release")
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)
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 >> 3) & 0xFF)
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
self.send_data(y & 0xFF)
self.send_data((y >> 8) & 0xFF)
self.ReadBusy()
def init(self, lut):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.send_command(0x01) # DRIVER_OUTPUT_CONTROL
self.send_data((EPD_HEIGHT - 1) & 0xFF)
self.send_data(((EPD_HEIGHT - 1) >> 8) & 0xFF)
self.send_data(0x00) # GD = 0 SM = 0 TB = 0
self.send_command(0x0C) # BOOSTER_SOFT_START_CONTROL
self.send_data(0xD7)
self.send_data(0xD6)
self.send_data(0x9D)
self.send_command(0x2C) # WRITE_VCOM_REGISTER
self.send_data(0xA8) # VCOM 7C
self.send_command(0x3A) # SET_DUMMY_LINE_PERIOD
self.send_data(0x1A) # 4 dummy lines per gate
self.send_command(0x3B) # SET_GATE_TIME
self.send_data(0x08) # 2us per line
self.send_command(0x11) # DATA_ENTRY_MODE_SETTING
self.send_data(0x03) # X increment Y increment
self.send_command(0x32) # WRITE_LUT_REGISTER
for i in range(0, len(lut)):
self.send_data(lut[i])
# EPD hardware init end
return 0
def getbuffer(self, image):
# logging.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()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height):
logging.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] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width):
logging.debug("Horizontal")
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):
if (image == None):
return
self.SetWindow(0, 0, self.width - 1, self.height - 1)
for j in range(0, self.height):
self.SetCursor(0, j)
self.send_command(0x24) # WRITE_RAM
for i in range(0, int(self.width / 8)):
self.send_data(image[i + j * int(self.width / 8)])
self.TurnOnDisplay()
def Clear(self, color):
self.SetWindow(0, 0, self.width - 1, self.height - 1)
for j in range(0, self.height):
self.SetCursor(0, j)
self.send_command(0x24) # WRITE_RAM
for i in range(0, int(self.width / 8)):
self.send_data(color)
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x10) # DEEP_SLEEP_MODE
self.send_data(0x01)
epdconfig.module_exit()
### END OF FILE ###

View File

@ -1,154 +0,0 @@
# /*****************************************************************************
# * | File : epdconfig.py
# * | Author : Waveshare team
# * | Function : Hardware underlying interface
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-06-21
# * | 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
class RaspberryPi:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
def __init__(self):
import spidev
import RPi.GPIO
self.GPIO = RPi.GPIO
# SPI device, bus = 0, device = 0
self.SPI = spidev.SpiDev(0, 0)
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.max_speed_hz = 4000000
self.SPI.mode = 0b00
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.close()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
class JetsonNano:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
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 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.BUSY_PIN, self.GPIO.IN)
self.SPI.SYSFS_software_spi_begin()
return 0
def module_exit(self):
logging.debug("spi end")
self.SPI.SYSFS_software_spi_end()
logging.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.cleanup()
if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
implementation = RaspberryPi()
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 ###

View File

@ -91,9 +91,9 @@ class EPD:
def SetWindow(self):
self.send_command(0x61) # 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(self.Source_BITS / 256)
self.send_data(int(self.Source_BITS / 256))
self.send_data(self.Source_BITS % 256)
self.send_data(self.Gate_BITS / 256)
self.send_data(int(self.Gate_BITS / 256))
self.send_data(self.Gate_BITS % 256)
def TurnOnDisplay(self):
@ -166,20 +166,21 @@ class EPD:
def getbuffer(self, image):
# Create a pallette with the 4 colors supported by the panel
global image_temp
pal_image = Image.new("P", (1, 1))
pal_image.putpalette((0, 0, 0, 255, 255, 255, 255, 255, 0, 255, 0, 0) + (0, 0, 0) * 252)
# Check if we need to rotate the image
imwidth, imheight = image.size
if (imwidth == self.width and imheight == self.height):
if imwidth == self.width and imheight == self.height:
image_temp = image
elif (imwidth == self.height and imheight == self.width):
elif imwidth == self.height and imheight == self.width:
image_temp = image.rotate(90, expand=True)
else:
logger.warning(
"Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height))
# Convert the soruce image to the 4 colors, dithering if needed
# Convert the source image to the 4 colors, dithering if needed
image_4color = image_temp.convert("RGB").quantize(palette=pal_image)
buf_4color = bytearray(image_4color.tobytes('raw'))

View File

@ -1,11 +1,11 @@
# *****************************************************************************
# * | File : epd2in13b_V4.py
# * | File : epd2in66b.py
# * | Author : Waveshare team
# * | Function : Electronic paper driver
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2022-04-21
# * | This version: V1.1
# * | Date : 2022-08-9
# # | Info : python demo
# -----------------------------------------------------------------------------
# Permission is hereby granted, free of charge, to any person obtaining a copy
@ -28,11 +28,11 @@
#
import logging
from . import epdconfig
from .. import epdconfig
# Display resolution
EPD_WIDTH = 122
EPD_HEIGHT = 250
EPD_WIDTH = 152
EPD_HEIGHT = 296
logger = logging.getLogger(__name__)
@ -46,23 +46,21 @@ class EPD:
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
# hardware reset
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(20)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(2)
epdconfig.delay_ms(5)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(20)
epdconfig.delay_ms(200)
# send 1 byte command
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)
# send 1 byte data
def send_data(self, data):
epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0)
@ -76,129 +74,116 @@ class EPD:
epdconfig.spi_writebyte2(data)
epdconfig.digital_write(self.cs_pin, 1)
# judge e-Paper whether is busy
def busy(self):
def ReadBusy(self):
logger.debug("e-Paper busy")
while (epdconfig.digital_read(self.busy_pin) != 0):
epdconfig.delay_ms(10)
while (epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(20)
logger.debug("e-Paper busy release")
# set the display window
def set_windows(self, xstart, ystart, xend, yend):
self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
self.send_data((xstart >> 3) & 0xff)
self.send_data((xend >> 3) & 0xff)
self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
self.send_data(ystart & 0xff)
self.send_data((ystart >> 8) & 0xff)
self.send_data(yend & 0xff)
self.send_data((yend >> 8) & 0xff)
# set the display cursor(origin)
def set_cursor(self, xstart, ystart):
self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
self.send_data(xstart & 0xff)
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
self.send_data(ystart & 0xff)
self.send_data((ystart >> 8) & 0xff)
# initialize
def init(self):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.busy()
self.send_command(0x12) # SWRESET
self.busy()
self.send_command(0x12)
epdconfig.delay_ms(30)
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_command(0x11) # setting gaet number
self.send_data(0x03)
self.set_windows(0, 0, self.width - 1, self.height - 1)
self.set_cursor(0, 0)
self.setWindows(0, 0, self.width - 1, self.height - 1)
self.send_command(0x3C) # BorderWavefrom
self.send_data(0x05)
self.send_command(0x18) # Read built-in temperature sensor
self.send_command(0x21)
self.send_data(0x00)
self.send_data(0x80)
self.send_command(0x21) # Display update control
self.send_data(0x80)
self.send_data(0x80)
self.busy()
self.setCursor(0, 0)
self.ReadBusy()
return 0
# turn on display
def ondisplay(self):
def setWindows(self, Xstart, Ystart, Xend, Yend):
self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
self.send_data((Xstart >> 3) & 0x1F)
self.send_data((Xend >> 3) & 0x1F)
self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
self.send_data(Ystart & 0xFF)
self.send_data((Ystart >> 8) & 0x01)
self.send_data(Yend & 0xFF)
self.send_data((Yend >> 8) & 0x01)
def setCursor(self, Xstart, Ystart):
self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
self.send_data(Xstart & 0x1F)
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
self.send_data(Ystart & 0xFF)
self.send_data((Ystart >> 8) & 0x01)
def turnon_display(self):
self.send_command(0x20)
self.busy()
self.ReadBusy()
# image converted to bytearray
def getbuffer(self, image):
img = image
imwidth, imheight = img.size
# 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):
img = img.convert('1')
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] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
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'))
logger.debug("Horizontal")
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
# display image
def display(self, imageblack, imagered):
def display(self, Blackimage, Redimage):
if (Blackimage == None or Redimage == None):
return
Redimage_1 = [0x00] * len(Redimage)
for i in range(len(Redimage)):
Redimage_1[i] = ~Redimage[i]
self.send_command(0x24)
self.send_data2(imageblack)
self.send_data2(Blackimage)
self.send_command(0x26)
self.send_data2(imagered)
self.send_data2(Redimage_1)
self.ondisplay()
self.turnon_display()
# display white image
def clear(self):
if self.width % 8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
buf = [0xff] * (int(linewidth * self.height))
self.send_command(0x24)
self.send_data2(buf)
self.send_command(0x26)
self.send_data2(buf)
self.ondisplay()
# Compatible with older version functions
def Clear(self):
self.clear()
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([0x00] * int(self.height * linewidth))
self.turnon_display()
# sleep
def sleep(self):
self.send_command(0x10) # DEEP_SLEEP
self.send_data(0x01) # check code
self.send_command(0X10) # DEEP_SLEEP_MODE
self.send_data(0x01)
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###

View File

@ -498,7 +498,7 @@ class EPD:
self.ReadBusy()
# pass
def Clear(self, color):
def Clear(self):
self.send_command(0x10)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF)

View File

@ -517,4 +517,5 @@ class EPD:
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###
### END OF FILE ###

View File

@ -28,7 +28,7 @@
#
import logging
from .. import epdconfig
from . import epdconfig
# Display resolution
EPD_WIDTH = 128

View File

@ -184,7 +184,7 @@ class EPD:
self.send_command(0x01) # Driver output control
self.send_data((self.height - 1) % 256)
self.send_data((self.height - 1) / 256)
self.send_data((self.height - 1) // 256)
self.send_data(0x00)
self.send_command(0x11) # data entry mode

View File

@ -417,7 +417,7 @@ class EPD:
self.send_command(0x20)
self.ReadBusy()
def Clear(self, color, mode):
def Clear(self, mode):
self.send_command(0x4E)
self.send_data(0x00)
self.send_data(0x00)

View File

@ -34,7 +34,7 @@ from PIL import Image
import RPi.GPIO as GPIO
# Display resolution
EPD_WIDTH = 400
EPD_WIDTH = 400
EPD_HEIGHT = 300
GRAY1 = 0xff # white

View File

@ -29,7 +29,7 @@
import logging
from .. import epdconfig
from . import epdconfig
# Display resolution
EPD_WIDTH = 800

View File

@ -1,11 +1,11 @@
# *****************************************************************************
# * | File : epd7in5.py
# * | File : epd4in26.py
# * | Author : Waveshare team
# * | Function : Electronic paper driver
# * | Info :
# *----------------
# * | This version: V4.0
# * | Date : 2019-06-20
# * | This version: V1.0
# * | Date : 2023-12-20
# # | Info : python demo
# -----------------------------------------------------------------------------
# Permission is hereby granted, free of charge, to any person obtaining a copy
@ -29,11 +29,16 @@
import logging
from .. import epdconfig
from . import epdconfig
# Display resolution
EPD_WIDTH = 880
EPD_HEIGHT = 528
EPD_WIDTH = 800
EPD_HEIGHT = 480
GRAY1 = 0xff # white
GRAY2 = 0xC0
GRAY3 = 0x80 # gray
GRAY4 = 0x00 # Blackest
logger = logging.getLogger(__name__)
@ -46,15 +51,39 @@ class EPD:
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
LUT_DATA_4Gray = [ # #112bytes
0x80, 0x48, 0x4A, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0A, 0x48, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x88, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xA8, 0x48, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x1E, 0x1C, 0x02, 0x00,
0x05, 0x01, 0x05, 0x01, 0x02,
0x08, 0x01, 0x01, 0x04, 0x04,
0x00, 0x02, 0x00, 0x02, 0x01,
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, 0x01,
0x22, 0x22, 0x22, 0x22, 0x22,
0x17, 0x41, 0xA8, 0x32, 0x30,
0x00, 0x00]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
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(200)
epdconfig.delay_ms(20)
def send_command(self, command):
epdconfig.digital_write(self.dc_pin, 0)
@ -71,7 +100,7 @@ class EPD:
def send_data2(self, data):
epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte2(data)
epdconfig.SPI.writebytes2(data)
epdconfig.digital_write(self.cs_pin, 1)
def ReadBusy(self):
@ -79,103 +108,409 @@ class EPD:
busy = epdconfig.digital_read(self.busy_pin)
while (busy == 1):
busy = epdconfig.digital_read(self.busy_pin)
epdconfig.delay_ms(200)
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 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_Part(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(0xC7)
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
self.send_data(x_start & 0xFF)
self.send_data((x_start >> 8) & 0x03)
self.send_data(x_end & 0xFF)
self.send_data((x_end >> 8) & 0x03)
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_data((x >> 8) & 0x03)
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
self.send_data(y & 0xFF)
self.send_data((y >> 8) & 0xFF)
def init(self):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.ReadBusy()
self.ReadBusy();
self.send_command(0x12); # SWRESET
self.ReadBusy();
self.send_command(0x12) # SWRESET
self.ReadBusy()
self.send_command(0x46); # Auto Write Red RAM
self.send_data(0xf7);
self.ReadBusy();
self.send_command(0x47); # Auto Write B/W RAM
self.send_data(0xf7);
self.ReadBusy();
self.send_command(0x18) # use the internal temperature sensor
self.send_data(0x80)
self.send_command(0x0C); # Soft start setting
self.send_data2([0xAE, 0xC7, 0xC3, 0xC0, 0x40])
self.send_command(0x0C) # set soft start
self.send_data(0xAE)
self.send_data(0xC7)
self.send_data(0xC3)
self.send_data(0xC0)
self.send_data(0x80)
self.send_command(0x01); # Set MUX as 527
self.send_data2([0xAF, 0x02, 0x01])
self.send_command(0x01) # drive output control
self.send_data((self.height - 1) % 256) # Y
self.send_data((self.height - 1) // 256) # Y
self.send_data(0x02)
self.send_command(0x11); # Data entry mode
self.send_data(0x01);
self.send_command(0x3C) # Border Border setting
self.send_data(0x01)
self.send_command(0x44);
self.send_data2([0x00, 0x00, 0x6F, 0x03]) # RAM x address start at 0
self.send_command(0x45);
self.send_data2([0xAF, 0x02, 0x00, 0x00])
self.send_command(0x11) # data entry mode
self.send_data(0x01) # X-mode x+ y-
self.send_command(0x3C); # VBD
self.send_data(0x05); # LUT1, for white
self.SetWindow(0, self.height - 1, self.width - 1, 0)
self.send_command(0x18);
self.send_data(0X80);
self.SetCursor(0, 0)
self.ReadBusy()
self.send_command(0x22);
self.send_data(0XB1); # Load Temperature and waveform setting.
self.send_command(0x20);
self.ReadBusy();
# EPD hardware init end
return 0
self.send_command(0x4E); # set RAM x address count to 0;
self.send_data2([0x00, 0x00])
self.send_command(0x4F);
self.send_data2([0x00, 0x00])
def init_Fast(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(0x18) # use the internal temperature sensor
self.send_data(0x80)
self.send_command(0x0C) # set soft start
self.send_data(0xAE)
self.send_data(0xC7)
self.send_data(0xC3)
self.send_data(0xC0)
self.send_data(0x80)
self.send_command(0x01) # drive output control
self.send_data((self.height - 1) % 256) # Y
self.send_data((self.height - 1) // 256) # Y
self.send_data(0x02)
self.send_command(0x3C) # Border Border setting
self.send_data(0x01)
self.send_command(0x11) # data entry mode
self.send_data(0x01) # X-mode x+ y-
self.SetWindow(0, self.height - 1, self.width - 1, 0)
self.SetCursor(0, 0)
self.ReadBusy()
# TEMP (1.5s)
self.send_command(0x1A)
self.send_data(0x5A)
self.send_command(0x22)
self.send_data(0x91)
self.send_command(0x20)
self.ReadBusy()
# EPD hardware init end
return 0
def Lut(self):
self.send_command(0x32)
for count in range(0, 105):
self.send_data(self.LUT_DATA_4Gray[count])
self.send_command(0x03) # VGH
self.send_data(self.LUT_DATA_4Gray[105])
self.send_command(0x04) #
self.send_data(self.LUT_DATA_4Gray[106]) # VSH1
self.send_data(self.LUT_DATA_4Gray[107]) # VSH2
self.send_data(self.LUT_DATA_4Gray[108]) # VSL
self.send_command(0x2C) # VCOM Voltage
self.send_data(self.LUT_DATA_4Gray[109]) # 0x1C
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(0x18) # use the internal temperature sensor
self.send_data(0x80)
self.send_command(0x0C) # set soft start
self.send_data(0xAE)
self.send_data(0xC7)
self.send_data(0xC3)
self.send_data(0xC0)
self.send_data(0x80)
self.send_command(0x01) # drive output control
self.send_data((self.height - 1) % 256) # Y
self.send_data((self.height - 1) // 256) # Y
self.send_data(0x02)
self.send_command(0x3C) # Border Border setting
self.send_data(0x01)
self.send_command(0x11) # data entry mode
self.send_data(0x01) # X-mode x+ y-
self.SetWindow(0, self.height - 1, self.width - 1, 0)
self.SetCursor(0, 0)
self.ReadBusy()
self.Lut()
# EPD hardware init end
return 0
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):
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 [0xff] * int(self.width * self.height / 8)
# 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
buf = bytearray(img.tobytes('raw'))
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):
self.send_command(0x4F);
self.send_data2([0x00, 0x00])
self.send_command(0x24);
self.send_data2(image)
self.send_command(0x22);
self.send_data(0xF7); # Load LUT from MCU(0x32)
self.send_command(0x20);
epdconfig.delay_ms(10);
self.ReadBusy();
def Clear(self):
buf = [0xff] * int(self.width * self.height / 8)
self.send_command(0x4F);
self.send_data2([0x00, 0x00])
self.send_command(0x24)
self.send_data2(buf)
self.send_data2(image)
self.TurnOnDisplay()
def display_Base(self, image):
self.send_command(0x24)
self.send_data2(image)
self.send_command(0x26)
self.send_data2(buf)
self.send_data2(image)
self.send_command(0x22);
self.send_data(0xF7); # Load LUT from MCU(0x32)
self.send_command(0x20);
epdconfig.delay_ms(10);
self.ReadBusy();
self.TurnOnDisplay()
def display_Fast(self, image):
self.send_command(0x24)
self.send_data2(image)
self.TurnOnDisplay_Fast()
def display_Partial(self, Image):
# Reset
self.reset()
self.send_command(0x18) # BorderWavefrom
self.send_data(0x80)
self.send_command(0x3C) # BorderWavefrom
self.send_data(0x80)
self.send_command(0x01) # drive output control
self.send_data((self.height - 1) % 256) # Y
self.send_data((self.height - 1) // 256) # Y
self.send_command(0x11) # data entry mode
self.send_data(0x01) # X-mode x+ y-
self.SetWindow(0, self.height - 1, self.width - 1, 0)
self.SetCursor(0, 0)
self.send_command(0x24) # Write Black and White image to RAM
self.send_data2(Image)
self.TurnOnDisplay_Part()
def display_4Gray(self, image):
self.send_command(0x24)
for i in range(0, 48000): # 5808*4 46464
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, 48000): # 5808*4 46464
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_4GRAY()
def Clear(self):
self.send_command(0x24)
self.send_data2([0xFF] * (int(self.width / 8) * self.height))
self.send_command(0x26)
self.send_data2([0xFF] * (int(self.width / 8) * self.height))
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x10);
self.send_data(0x01);
self.send_command(0x10) # DEEP_SLEEP
self.send_data(0x01)
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###
### END OF FILE ###

View File

@ -243,7 +243,7 @@ class EPD:
else:
Xend = Xend // 8 * 8 + 1
Width = (Xend - Xstart) / 8
Width = (Xend - Xstart) // 8
Height = Yend - Ystart
self.send_command(0x50)

View File

@ -484,7 +484,7 @@ class EPD:
else:
Xend = Xend // 8 * 8 + 1
Width = (Xend - Xstart) / 8
Width = (Xend - Xstart) // 8
Height = Yend - Ystart
self.send_command(0x50)

View File

@ -81,59 +81,59 @@ class EPD:
self.reset()
self.send_command(0x12); # SWRESET
self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x12) # SWRESET
self.ReadBusy() # waiting for the electronic paper IC to release the idle signal
self.send_command(0x46); # Auto Write RAM
self.send_data(0xF7);
self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x46) # Auto Write RAM
self.send_data(0xF7)
self.ReadBusy() # waiting for the electronic paper IC to release the idle signal
self.send_command(0x47); # Auto Write RAM
self.send_data(0xF7);
self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x47) # Auto Write RAM
self.send_data(0xF7)
self.ReadBusy() # waiting for the electronic paper IC to release the idle signal
self.send_command(0x0C); # Soft start setting
self.send_data(0xAE);
self.send_data(0xC7);
self.send_data(0xC3);
self.send_data(0xC0);
self.send_data(0x40);
self.send_command(0x0C) # Soft start setting
self.send_data(0xAE)
self.send_data(0xC7)
self.send_data(0xC3)
self.send_data(0xC0)
self.send_data(0x40)
self.send_command(0x01); # Set MUX as 527
self.send_data(0xAF);
self.send_data(0x02);
self.send_data(0x01);
self.send_command(0x01) # Set MUX as 527
self.send_data(0xAF)
self.send_data(0x02)
self.send_data(0x01)
self.send_command(0x11); # Data entry mode
self.send_data(0x01);
self.send_command(0x11) # Data entry mode
self.send_data(0x01)
self.send_command(0x44);
self.send_data(0x00); # RAM x address start at 0
self.send_data(0x00);
self.send_data(0x6F); # RAM x address end at 36Fh -> 879
self.send_data(0x03);
self.send_command(0x45);
self.send_data(0xAF); # RAM y address start at 20Fh;
self.send_data(0x02);
self.send_data(0x00); # RAM y address end at 00h;
self.send_data(0x00);
self.send_command(0x44)
self.send_data(0x00) # RAM x address start at 0
self.send_data(0x00)
self.send_data(0x6F) # RAM x address end at 36Fh -> 879
self.send_data(0x03)
self.send_command(0x45)
self.send_data(0xAF) # RAM y address start at 20Fh
self.send_data(0x02)
self.send_data(0x00) # RAM y address end at 00h
self.send_data(0x00)
self.send_command(0x3C); # VBD
self.send_data(0x01); # LUT1, for white
self.send_command(0x3C) # VBD
self.send_data(0x01) # LUT1, for white
self.send_command(0x18);
self.send_data(0X80);
self.send_command(0x22);
self.send_data(0XB1); # Load Temperature and waveform setting.
self.send_command(0x20);
self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x18)
self.send_data(0X80)
self.send_command(0x22)
self.send_data(0XB1) # Load Temperature and waveform setting.
self.send_command(0x20)
self.ReadBusy() # waiting for the electronic paper IC to release the idle signal
self.send_command(0x4E);
self.send_data(0x00);
self.send_data(0x00);
self.send_command(0x4F);
self.send_data(0xAF);
self.send_data(0x02);
self.send_command(0x4E)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x4F)
self.send_data(0xAF)
self.send_data(0x02)
return 0
@ -162,44 +162,44 @@ class EPD:
return buf
def display(self, imageblack, imagered):
self.send_command(0x4F);
self.send_data(0xAf);
self.send_command(0x4F)
self.send_data(0xAf)
self.send_command(0x24)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(imageblack[i]);
self.send_data(imageblack[i])
self.send_command(0x26)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(~imagered[i]);
self.send_data(~imagered[i])
self.send_command(0x22);
self.send_data(0xC7); # Load LUT from MCU(0x32)
self.send_command(0x20);
epdconfig.delay_ms(200); # !!!The delay here is necessary, 200uS at least!!!
self.ReadBusy();
self.send_command(0x22)
self.send_data(0xC7) # Load LUT from MCU(0x32)
self.send_command(0x20)
epdconfig.delay_ms(200) # !!!The delay here is necessary, 200uS at least!!!
self.ReadBusy()
def Clear(self):
self.send_command(0x4F);
self.send_data(0xAf);
self.send_command(0x4F)
self.send_data(0xAf)
self.send_command(0x24)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xff);
self.send_data(0xff)
self.send_command(0x26)
for i in range(0, int(self.width * self.height / 8)):
self.send_data(0x00);
self.send_data(0x00)
self.send_command(0x22);
self.send_data(0xC7); # Load LUT from MCU(0x32)
self.send_command(0x20);
epdconfig.delay_ms(200); # !!!The delay here is necessary, 200uS at least!!!
self.ReadBusy();
self.send_command(0x22)
self.send_data(0xC7) # Load LUT from MCU(0x32)
self.send_command(0x20)
epdconfig.delay_ms(200) # !!!The delay here is necessary, 200uS at least!!!
self.ReadBusy()
def sleep(self):
self.send_command(0x10); # deep sleep
self.send_data(0x01);
self.send_command(0x10) # deep sleep
self.send_data(0x01)
epdconfig.delay_ms(2000)
epdconfig.module_exit()

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class OledHat(DisplayImpl):
def __init__(self, config):
super(OledHat, self).__init__(config, 'oledhat')
self._display = None
def layout(self):
fonts.setup(8, 8, 8, 10, 10, 8)

View File

@ -8,7 +8,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Papirus(DisplayImpl):
def __init__(self, config):
super(Papirus, self).__init__(config, 'papirus')
self._display = None
def layout(self):
fonts.setup(10, 8, 10, 23, 25, 9)

View File

@ -3,12 +3,12 @@ import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
import os,time
import time
class Spotpear24inch(DisplayImpl):
def __init__(self, config):
super(Spotpear24inch, self).__init__(config, 'spotpear24inch')
self._display = None
def layout(self):
fonts.setup(12, 10, 12, 70, 25, 9)

View File

@ -3,12 +3,12 @@ import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
import os,time
import time
class Spotpear24inch(DisplayImpl):
def __init__(self, config):
super(Spotpear24inch, self).__init__(config, 'spotpear24inch')
self._display = None
def layout(self):
fonts.setup(12, 10, 12, 70, 25, 9)

View File

@ -1,90 +0,0 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class WaveshareV1(DisplayImpl):
def __init__(self, config):
super(WaveshareV1, self).__init__(config, 'waveshare_1')
self._display = None
def layout(self):
if self.config['color'] == 'black':
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 250
self._layout['height'] = 122
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
else:
fonts.setup(10, 8, 10, 25, 25, 9)
self._layout['width'] = 212
self._layout['height'] = 104
self._layout['face'] = (0, 26)
self._layout['name'] = (5, 15)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (147, 0)
self._layout['line1'] = [0, 12, 212, 12]
self._layout['line2'] = [0, 92, 212, 92]
self._layout['friend_face'] = (0, 76)
self._layout['friend_name'] = (40, 78)
self._layout['shakes'] = (0, 93)
self._layout['mode'] = (187, 93)
self._layout['status'] = {
'pos': (91, 15),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
if self.config['color'] == 'black':
logging.info("initializing waveshare v1 display in monochromatic mode")
from pwnagotchi.ui.hw.libs.waveshare.v1.epd2in13 import EPD
self._display = EPD()
self._display.init(self._display.lut_full_update)
self._display.Clear(0xFF)
self._display.init(self._display.lut_partial_update)
elif self.config['color'] == 'fastAndFurious':
logging.info("initializing waveshare v1 3-color display in FAST MODE")
logging.info("THIS MAY BE POTENTIALLY DANGEROUS. NO WARRANTY IS PROVIDED")
logging.info("USE THIS DISPLAY IN THIS MODE AT YOUR OWN RISK")
from pwnagotchi.ui.hw.libs.waveshare.v1.epd2in13bcFAST import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
else:
logging.info("initializing waveshare v1 display 3-color mode")
from pwnagotchi.ui.hw.libs.waveshare.v1.epd2in13bc import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
if self.config['color'] == 'black':
buf = self._display.getbuffer(canvas)
self._display.display(buf)
elif self.config['color'] == 'fastAndFurious':
buf_black = self._display.getbuffer(canvas)
self._display.DisplayPartial(buf_black)
else:
buf_black = self._display.getbuffer(canvas)
self._display.displayBlack(buf_black)
def clear(self):
self._display.Clear(0xff)

View File

@ -0,0 +1,45 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare13in3k(DisplayImpl):
def __init__(self, config):
super(Waveshare13in3k, self).__init__(config, 'waveshare13in3k')
def layout(self):
fonts.setup(10, 8, 10, 18, 25, 9)
self._layout['width'] = 960
self._layout['height'] = 680
self._layout['face'] = (0, 43)
self._layout['name'] = (0, 14)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (0, 71)
self._layout['uptime'] = (0, 25)
self._layout['line1'] = [0, 12, 960, 12]
self._layout['line2'] = [0, 116, 960, 116]
self._layout['friend_face'] = (12, 88)
self._layout['friend_name'] = (1, 103)
self._layout['shakes'] = (26, 117)
self._layout['mode'] = (0, 117)
self._layout['status'] = {
'pos': (65, 26),
'font': fonts.status_font(fonts.Small),
'max': 12
}
return self._layout
def initialize(self):
logging.info("initializing waveshare 13.3k inch lcd display")
from pwnagotchi.ui.hw.libs.waveshare.v13in3k.epd13in3k import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def clear(self):
self._display.Clear()

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare144lcd(DisplayImpl):
def __init__(self, config):
super(Waveshare144lcd, self).__init__(config, 'waveshare144lcd')
self._display = None
def layout(self):
fonts.setup(10, 8, 10, 18, 25, 9)
@ -42,5 +41,4 @@ class Waveshare144lcd(DisplayImpl):
self._display.display(canvas)
def clear(self):
pass
#self._display.clear()
self._display.clear()

View File

@ -1,47 +0,0 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare154inch(DisplayImpl):
def __init__(self, config):
super(Waveshare154inch, self).__init__(config, 'waveshare_1_54inch')
self._display = None
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
self._layout['width'] = 200
self._layout['height'] = 200
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (135, 0)
self._layout['line1'] = [0, 14, 200, 14]
self._layout['line2'] = [0, 186, 200, 186]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 187)
self._layout['mode'] = (170, 187)
self._layout['status'] = {
'pos': (5, 90),
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing waveshare v154 display")
from pwnagotchi.ui.hw.libs.waveshare.v154inch.epd1in54b import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf, None)
def clear(self):
pass
#self._display.Clear()

View File

@ -0,0 +1,45 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare1in02(DisplayImpl):
def __init__(self, config):
super(Waveshare1in02, self).__init__(config, 'waveshare1in02')
def layout(self):
fonts.setup(10, 8, 10, 18, 25, 9)
self._layout['width'] = 80
self._layout['height'] = 128
self._layout['face'] = (0, 43)
self._layout['name'] = (0, 14)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (0, 71)
self._layout['uptime'] = (0, 25)
self._layout['line1'] = [0, 12, 80, 12]
self._layout['line2'] = [0, 116, 80, 116]
self._layout['friend_face'] = (12, 88)
self._layout['friend_name'] = (1, 103)
self._layout['shakes'] = (26, 117)
self._layout['mode'] = (0, 117)
self._layout['status'] = {
'pos': (65, 26),
'font': fonts.status_font(fonts.Small),
'max': 12
}
return self._layout
def initialize(self):
logging.info("initializing waveshare 1.02 inch lcd display")
from pwnagotchi.ui.hw.libs.waveshare.v1in02.epd1in02 import EPD
self._display = EPD()
self._display.Init()
self._display.Clear()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf)
def clear(self):
self._display.Clear()

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare144lcd(DisplayImpl):
def __init__(self, config):
super(Waveshare144lcd, self).__init__(config, 'waveshare144lcd')
self._display = None
def layout(self):
fonts.setup(10, 8, 10, 18, 25, 9)
@ -42,5 +41,4 @@ class Waveshare144lcd(DisplayImpl):
self._display.display(canvas)
def clear(self):
pass
#self._display.clear()
self._display.clear()

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare154(DisplayImpl):
def __init__(self, config):
super(Waveshare154, self).__init__(config, 'waveshare1in54')
self._display = None
def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9)
@ -32,15 +31,16 @@ class Waveshare154(DisplayImpl):
return self._layout
def initialize(self):
logging.info("initializing waveshare v154 display")
logging.info("initializing waveshare v1in54 display")
from pwnagotchi.ui.hw.libs.waveshare.v1in54.epd1in54 import EPD
self._display = EPD()
self._display.init()
self._display.init(0x00)
self._display.Clear()
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.display(buf, None)
self._display.display(buf)
def clear(self):
# pass
self._display.Clear()

Some files were not shown because too many files have changed in this diff Show More