Compare commits

..

92 Commits

Author SHA1 Message Date
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
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
159 changed files with 3214 additions and 5167 deletions

21
.idea/deployment.xml generated
View File

@ -1,4 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <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> </project>

3
.idea/misc.xml generated
View File

@ -4,4 +4,7 @@
<option name="sdkName" value="Python 3.11 (pwnagotchi)" /> <option name="sdkName" value="Python 3.11 (pwnagotchi)" />
</component> </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 (pwnagotchi-torch-bookworm)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project> </project>

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: 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. Enter an appropriate name.
@ -19,7 +19,7 @@ Input http://localhost/ for Authorized redirect URIs.
Select the correct oauth scope: Select the correct oauth scope:
- drive - drive.file
- drive.install - drive.install
Click Create. Click Create.

View File

@ -7,9 +7,12 @@ It seems the Pi 5 is unable to run in monitor mode, will keep you updated on thi
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. 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.7), and let it auto-update from here on out. Download the latest image file [here](https://github.com/jayofelony/pwnagotchi-bookworm/releases/tag/v2.7.9), 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.** **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`. SSH credentials are `pi/raspberry`.

1
apt_packages.txt Normal file
View File

@ -0,0 +1 @@
hcxtools

View File

@ -50,6 +50,7 @@ def pwnagotchi_cli():
agent.mode = 'auto' agent.mode = 'auto'
agent.start() agent.start()
config = agent.config()
while True: while True:
try: try:
@ -66,6 +67,9 @@ def pwnagotchi_cli():
# for each ap on this channel # for each ap on this channel
for ap in aps: 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 # send an association frame in order to get for a PMKID
agent.associate(ap) agent.associate(ap)
# deauth all client stations in order to get a full handshake # deauth all client stations in order to get a full handshake
@ -157,7 +161,7 @@ def pwnagotchi_cli():
sys.exit(0) sys.exit(0)
if args.donate: 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) sys.exit(0)
if args.check_update: if args.check_update:
@ -172,10 +176,14 @@ def pwnagotchi_cli():
% (pwnagotchi.__version__, latest_ver)) % (pwnagotchi.__version__, latest_ver))
# input validation # input validation
if user_input.lower() in ('y', 'yes'): 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.") 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!") print("Okay, guess not!")
else:
print("Invalid input.")
else: else:
print("You are currently on the latest release, v%s." % pwnagotchi.__version__) print("You are currently on the latest release, v%s." % pwnagotchi.__version__)
sys.exit(0) sys.exit(0)

View File

@ -0,0 +1,15 @@
# Specifies amount of zram devices to create.
# By default, zramswap-start will use all available cores.
#CORES=1
# Specifies the amount of RAM that should be used for zram
# based on a percentage the total amount of available memory
PERCENTAGE=60
# Specifies a static amount of RAM that should be used for
# the ZRAM devices, this is in MiB
#ALLOCATION=256
# Specifies the priority for the swap devices, see swapon(2)
# for more details.
#PRIORITY=100

View File

@ -1,26 +0,0 @@
# /etc/dphys-swapfile - user settings for dphys-swapfile package
# author Neil Franklin, last modification 2010.05.05
# copyright ETH Zuerich Physics Departement
# use under either modified/non-advertising BSD or GPL license
# this file is sourced with . so full normal sh syntax applies
# the default settings are added as commented out CONF_*=* lines
# where we want the swapfile to be, this is the default
#CONF_SWAPFILE=/var/swap
# set size to absolute value, leaving empty (default) then uses computed value
# you most likely don't want this, unless you have an special disk situation
CONF_SWAPSIZE=2048
# set size to computed value, this times RAM size, dynamically adapts,
# guarantees that there is enough swap without wasting disk space on excess
#CONF_SWAPFACTOR=2
# restrict size (computed and absolute!) to maximally this limit
# can be set to empty for no limit, but beware of filled partitions!
# this is/was a (outdated?) 32bit kernel limit (in MBytes), do not overrun it
# but is also sensible on 64bit to prevent filling /var or even / partition
#CONF_MAXSWAP=2048

View File

@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
_hostname=$(hostname) _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
echo "(◕‿‿◕) $_hostname" echo "(☉_☉ ) $_hostname"
echo echo
echo " Hi! I'm a pwnagotchi $_version, please take good care of me!" 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!" 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 " You can restart me using"
echo " pwnkill" echo " pwnkill"
echo echo
echo " You learn more about me at https://pwnagotchi.ai/" echo " You can learn more about me at https://pwnagotchi.ai/"

View File

@ -56,7 +56,7 @@ stop_monitor_interface() {
ifconfig wlan0 up ifconfig wlan0 up
} }
# returns 0 if the specificed network interface is up # returns 0 if the specified network interface is up
is_interface_up() { is_interface_up() {
if grep -qi 'up' /sys/class/net/"$1"/operstate; then if grep -qi 'up' /sys/class/net/"$1"/operstate; then
return 0 return 0

View File

@ -7,6 +7,7 @@
kernel: kernel:
min: "6.1" min: "6.1"
full: "6.1.0-rpi7-rpi-v8" full: "6.1.0-rpi7-rpi-v8"
full_pi5: "6.1.0-rpi7-rpi-2712"
pwnagotchi: pwnagotchi:
hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}" hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}"
version: "{{ lookup('env', 'PWN_VERSION') | default('pwnagotchi-torch', true) }}" version: "{{ lookup('env', 'PWN_VERSION') | default('pwnagotchi-torch', true) }}"
@ -23,21 +24,17 @@
services: services:
enable: enable:
- bettercap.service - bettercap.service
- dphys-swapfile.service
- fstrim.timer - fstrim.timer
- pwnagotchi.service - pwnagotchi.service
- pwngrid-peer.service - pwngrid-peer.service
- zramswap.service
disable: disable:
- apt-daily-upgrade.service - apt-daily-upgrade.service
- apt-daily-upgrade.timer - apt-daily-upgrade.timer
- apt-daily.service - apt-daily.service
- apt-daily.timer - apt-daily.timer
- avahi-daemon.service
- avahi-daemon.socket
- bluetooth.service - bluetooth.service
- ifup@wlan0.service - ifup@wlan0.service
- triggerhappy.service
- wpa_supplicant.service
packages: packages:
caplets: caplets:
source: "https://github.com/jayofelony/caplets.git" source: "https://github.com/jayofelony/caplets.git"
@ -55,12 +52,20 @@
- libpcap0.8-dev_1.9.1-4_arm64.deb - libpcap0.8-dev_1.9.1-4_arm64.deb
- libpcap0.8_1.9.1-4_arm64.deb - libpcap0.8_1.9.1-4_arm64.deb
hold: hold:
- firmware-atheros
- firmware-brcm80211
- firmware-libertas
- firmware-misc-nonfree
- firmware-realtek
- libpcap-dev - libpcap-dev
- libpcap0.8 - libpcap0.8
- libpcap0.8-dev
- libpcap0.8-dbg - libpcap0.8-dbg
- libpcap0.8-dev
remove: remove:
- avahi-daemon - avahi-daemon
- dhpys-swapfile
- libcurl-ocaml-dev
- libssl-ocaml-dev
- nfs-common - nfs-common
- triggerhappy - triggerhappy
- wpasupplicant - wpasupplicant
@ -73,7 +78,6 @@
- build-essential - build-essential
- curl - curl
- dkms - dkms
- dphys-swapfile
- fbi - fbi
- flex - flex
- fonts-dejavu - fonts-dejavu
@ -84,6 +88,7 @@
- gawk - gawk
- gcc-arm-none-eabi - gcc-arm-none-eabi
- git - git
- hcxtools
- libatlas-base-dev - libatlas-base-dev
- libavcodec59 - libavcodec59
- libavformat59 - libavformat59
@ -93,6 +98,8 @@
- libc-ares-dev - libc-ares-dev
- libc6-dev - libc6-dev
- libcap-dev - libcap-dev
- libcurl-ocaml-dev
- libssl-ocaml-dev
- libdbus-1-dev - libdbus-1-dev
- libdbus-glib-1-dev - libdbus-glib-1-dev
- libeigen3-dev - libeigen3-dev
@ -161,17 +168,52 @@
- wl - wl
- xxd - xxd
- zlib1g-dev - zlib1g-dev
environment: - zram-tools
ARCHFLAGS: "-arch aarch64"
QEMU_UNAME: "{{ kernel.full }}"
tasks: 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 - name: Create pi user
copy: copy:
dest: /boot/firmware/userconf dest: /boot/firmware/userconf
content: | content: |
pi:$6$3jNr0GA9KIyt4hmM$efeVIopdMQ8DGgEPCWWlbx3mJJNAYci1lEXGdlky0xPyjqwKNbwTL5SrCcpb4144C4IvzWjn7Iv.QjqmU7iyT/ 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 - name: change hostname
lineinfile: lineinfile:
dest: /etc/hostname dest: /etc/hostname
@ -189,6 +231,7 @@
state: present state: present
when: hostname.changed when: hostname.changed
# Now we disable sap and a2dp, we don't use them on rpi
- name: disable sap plugin for bluetooth.service - name: disable sap plugin for bluetooth.service
lineinfile: lineinfile:
dest: /lib/systemd/system/bluetooth.service dest: /lib/systemd/system/bluetooth.service
@ -196,19 +239,6 @@
line: 'ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp' line: 'ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp'
state: present 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 # libpcap v1.9 - build from source
@ -242,35 +272,117 @@
dest: /usr/local/lib/libpcap.so.0.8 dest: /usr/local/lib/libpcap.so.0.8
state: link state: link
# 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
# Install nexmon to fix wireless scanning (takes 2.5G of space) # Install nexmon to fix wireless scanning (takes 2.5G of space)
- name: clone nexmon repository - name: clone nexmon repository
git: git:
repo: https://github.com/DrSchottky/nexmon.git repo: https://github.com/DrSchottky/nexmon.git
dest: /usr/local/src/nexmon dest: /usr/local/src/nexmon
- name: make firmware # FIRST WE BUILD DRIVER FOR RPi5
- name: make firmware, RPi5
shell: "source ./setup_env.sh && make" shell: "source ./setup_env.sh && make"
args: args:
executable: /bin/bash executable: /bin/bash
chdir: /usr/local/src/nexmon/ 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" shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make"
args: args:
executable: /bin/bash executable: /bin/bash
chdir: /usr/local/src/nexmon/ 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: copy:
src: /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/brcmfmac43455-sdio.bin src: /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/brcmfmac43455-sdio.bin
dest: /usr/lib/firmware/brcm/brcmfmac43455-sdio.bin dest: /usr/lib/firmware/brcm/brcmfmac43455-sdio.bin
follow: true follow: true
# NOW WE BUILD DRIVERS FOR RPiZero2W, RPi 3
- name: make firmware patch (bcm43436b0) - name: make firmware patch (bcm43436b0)
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make" shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make"
args: args:
executable: /bin/bash executable: /bin/bash
chdir: /usr/local/src/nexmon/ chdir: /usr/local/src/nexmon/
environment:
QEMU_UNAME: "{{ kernel.full }}"
ARCHFLAGS: "-arch aarch64"
- name: install new firmware (bcm43436b0) - name: install new firmware (bcm43436b0)
copy: copy:
@ -283,6 +395,17 @@
args: args:
executable: /bin/bash executable: /bin/bash
chdir: /usr/local/src/nexmon/ 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) - name: install new firmware (bcm43430a1)
copy: copy:
@ -313,13 +436,10 @@
- name: backup original driver - 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" 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 - name: load brcmfmac drivers
copy: command: "/sbin/depmod {{ kernel.full }}"
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko" environment:
dest: "/usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko" QEMU_UNAME: "{{ kernel.full }}"
- name : load brcmfmac drivers
command: "/sbin/depmod -a"
# To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation # To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation
- name: Delete nexmon content & directory - name: Delete nexmon content & directory
@ -477,41 +597,6 @@
state: absent state: absent
path: /etc/update-motd.d/10-uname 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 - name: Add pwnlog alias
lineinfile: lineinfile:
dest: /home/pi/.bashrc dest: /home/pi/.bashrc
@ -563,18 +648,6 @@
group: pi group: pi
recurse: true 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 - name: remove pre-collected packages zip
file: file:
path: /root/go_pkgs.tgz path: /root/go_pkgs.tgz
@ -595,11 +668,6 @@
state: absent state: absent
path: /root/.cache/pip path: /root/.cache/pip
- name: remove dependencies that are no longer required
apt:
autoremove: yes
when: removed.changed
- name: remove ssh keys - name: remove ssh keys
file: file:
state: absent state: absent
@ -612,6 +680,24 @@
args: args:
executable: /bin/bash 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: handlers:
- name: reload systemd services - name: reload systemd services
systemd: systemd:

View File

@ -1 +1 @@
__version__ = '2.6.8' __version__ = '2.8.0'

View File

@ -31,7 +31,6 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
AsyncTrainer.__init__(self, config) AsyncTrainer.__init__(self, config)
self._started_at = time.time() self._started_at = time.time()
self._filter = None if not config['main']['filter'] else re.compile(config['main']['filter'])
self._current_channel = 0 self._current_channel = 0
self._tot_aps = 0 self._tot_aps = 0
self._aps_on_channel = 0 self._aps_on_channel = 0
@ -164,11 +163,6 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
self.wait_for(recon_time, sleeping=False) 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): def set_access_points(self, aps):
self._access_points = aps self._access_points = aps
plugins.on('wifi_update', self, aps) plugins.on('wifi_update', self, aps)
@ -184,13 +178,12 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
for ap in s['wifi']['aps']: for ap in s['wifi']['aps']:
if ap['encryption'] == '' or ap['encryption'] == 'OPEN': if ap['encryption'] == '' or ap['encryption'] == 'OPEN':
continue continue
elif ap['hostname'] not in whitelist \ elif ap['hostname'] in whitelist or ap['mac'][:13].lower() in whitelist or ap['mac'].lower() in whitelist:
and ap['mac'].lower() not in whitelist \ continue
and ap['mac'][:8].lower() not in whitelist: else:
if self._filter_included(ap): aps.append(ap)
aps.append(ap)
except Exception as e: 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']) aps.sort(key=lambda ap: ap['channel'])
return self.set_access_points(aps) return self.set_access_points(aps)
@ -275,6 +268,10 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
self._save_recovery_data() self._save_recovery_data()
pwnagotchi.reboot() pwnagotchi.reboot()
def _restart(self):
self._save_recovery_data()
pwnagotchi.restart("AUTO")
def _save_recovery_data(self): def _save_recovery_data(self):
logging.warning("writing recovery data to %s ...", RECOVERY_DATA_FILE) logging.warning("writing recovery data to %s ...", RECOVERY_DATA_FILE)
with open(RECOVERY_DATA_FILE, 'w') as fp: with open(RECOVERY_DATA_FILE, 'w') as fp:
@ -365,8 +362,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
plugins.on('handshake', self, filename, ap_mac, sta_mac) plugins.on('handshake', self, filename, ap_mac, sta_mac)
else: else:
(ap, sta) = ap_and_station (ap, sta) = ap_and_station
self._last_pwnd = ap['hostname'] if ap['hostname'] != '' and ap[ self._last_pwnd = ap['hostname'] if ap['hostname'] != '' and ap['hostname'] != '<hidden>' else ap_mac
'hostname'] != '<hidden>' else ap_mac
logging.warning( logging.warning(
"!!! captured new handshake on channel %d, %d dBm: %s (%s) -> %s [%s (%s)] !!!", "!!! captured new handshake on channel %d, %d dBm: %s (%s) -> %s [%s (%s)] !!!",
ap['channel'], ap['rssi'], sta['mac'], sta['vendor'], ap['hostname'], ap['mac'], ap['vendor']) ap['channel'], ap['rssi'], sta['mac'], sta['vendor'], ap['hostname'], ap['mac'], ap['vendor'])
@ -427,7 +423,6 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
if self.is_stale(): if self.is_stale():
logging.debug("recon is stale, skipping assoc(%s)", ap['mac']) logging.debug("recon is stale, skipping assoc(%s)", ap['mac'])
return return
if throttle == -1 and "throttle_a" in self._config['personality']: if throttle == -1 and "throttle_a" in self._config['personality']:
throttle = self._config['personality']['throttle_a'] throttle = self._config['personality']['throttle_a']

View File

@ -59,7 +59,8 @@ def load(config, agent, epoch, from_disk=True):
return a2c return a2c
except Exception as e: 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.") logging.info("[AI] Deleting brain and restarting.")
os.system("rm /root/brain.nn && service pwnagotchi restart") 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()) plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']: 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) logging.critical("%d epochs without visible access points -> restarting ...", self._epoch.blind_for)
self._reboot() self._restart()
self._epoch.blind_for = 0 self._epoch.blind_for = 0

View File

@ -1,5 +1,11 @@
main.name = "pwnagotchi" main.name = "pwnagotchi"
main.lang = "en" 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.confd = "/etc/pwnagotchi/conf.d/"
main.custom_plugin_repos = [ main.custom_plugin_repos = [
"https://github.com/jayofelony/pwnagotchi-torch-plugins/archive/master.zip", "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.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.enabled = true
main.plugins.auto-update.install = true main.plugins.auto-update.install = true
main.plugins.auto-update.interval = 1 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.enabled = true
main.plugins.grid.report = true main.plugins.grid.report = true
main.plugins.grid.exclude = [
"YourHomeNetworkHere"
]
main.plugins.logtail.enabled = false main.plugins.logtail.enabled = false
main.plugins.logtail.max-lines = 10000 main.plugins.logtail.max-lines = 10000
@ -73,10 +80,6 @@ main.plugins.onlinehashcrack.enabled = false
main.plugins.onlinehashcrack.email = "" main.plugins.onlinehashcrack.email = ""
main.plugins.onlinehashcrack.dashboard = "" main.plugins.onlinehashcrack.dashboard = ""
main.plugins.onlinehashcrack.single_files = false 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.enabled = false
main.plugins.pisugar2.shutdown = 5 main.plugins.pisugar2.shutdown = 5
@ -100,26 +103,19 @@ main.plugins.webgpsmap.enabled = false
main.plugins.wigle.enabled = false main.plugins.wigle.enabled = false
main.plugins.wigle.api_key = "" main.plugins.wigle.api_key = ""
main.plugins.wigle.whitelist = [] main.plugins.wigle.donate = false
main.plugins.wigle.donate = true
main.plugins.wpa-sec.enabled = false main.plugins.wpa-sec.enabled = false
main.plugins.wpa-sec.api_key = "" main.plugins.wpa-sec.api_key = ""
main.plugins.wpa-sec.api_url = "https://wpa-sec.stanev.org" main.plugins.wpa-sec.api_url = "https://wpa-sec.stanev.org"
main.plugins.wpa-sec.download_results = false main.plugins.wpa-sec.download_results = false
main.plugins.wpa-sec.whitelist = []
main.iface = "wlan0mon" main.iface = "wlan0mon"
main.mon_start_cmd = "/usr/bin/monstart" main.mon_start_cmd = "/usr/bin/monstart"
main.mon_stop_cmd = "/usr/bin/monstop" main.mon_stop_cmd = "/usr/bin/monstop"
main.mon_max_blind_epochs = 50 main.mon_max_blind_epochs = 50
main.no_restart = false main.no_restart = false
main.whitelist = [
"EXAMPLE_NETWORK",
"ANOTHER_EXAMPLE_NETWORK",
"fo:od:ba:be:fo:od",
"fo:od:ba"
]
main.filter = "" main.filter = ""
main.log.path = "/home/pi/logs/pwnagotchi.log" main.log.path = "/home/pi/logs/pwnagotchi.log"

View File

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

@ -3,12 +3,12 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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']) source_path = "%s-%s" % (source_path, update['available'])
# setup.py is going to install data files for us # 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 return True
@ -212,7 +212,7 @@ class AutoUpdate(plugins.Plugin):
if install(display, update): if install(display, update):
num_installed += 1 num_installed += 1
else: 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") logging.info("[update] done")

View File

@ -21,9 +21,6 @@ class FixServices(plugins.Plugin):
__help__ = """ __help__ = """
Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG. Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG.
""" """
__dependencies__ = {
'pip': ['scapy']
}
__defaults__ = { __defaults__ = {
'enabled': True, 'enabled': True,
} }
@ -46,8 +43,7 @@ class FixServices(plugins.Plugin):
logging.info("[Fix_Services] plugin loaded.") logging.info("[Fix_Services] plugin loaded.")
def on_ready(self, agent): def on_ready(self, agent):
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10', '-k'], last_lines = self.get_last_lines('journalctl', ['-n10', '-k'], 10)
stdout=subprocess.PIPE).stdout))[-10:])
try: try:
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True) cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output)) logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
@ -99,14 +95,23 @@ class FixServices(plugins.Plugin):
logging.error("[Fix_Services]SYSLOG wifi.recon flip fail: %s" % err) logging.error("[Fix_Services]SYSLOG wifi.recon flip fail: %s" % err)
self._tryTurningItOffAndOnAgain(agent) 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): def on_epoch(self, agent, epoch, epoch_data):
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)
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'], other_last_lines = self.get_last_lines('journalctl', ['-n10'], 10)
stdout=subprocess.PIPE).stdout))[-10:]) other_other_last_lines = self.get_last_lines('tail', ['-n10', '/home/pi/logs/pwnagotchi.log'], 10)
other_other_last_lines = ''.join(
list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/var/log/pwnagotchi.log'],
stdout=subprocess.PIPE).stdout))[-10:])
# don't check if we ran a reset recently # don't check if we ran a reset recently
logging.debug("[Fix_Services]**** epoch") logging.debug("[Fix_Services]**** epoch")
if time.time() - self.LASTTRY > 180: if time.time() - self.LASTTRY > 180:

View File

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

View File

@ -20,6 +20,7 @@ class GPS(plugins.Plugin):
def __init__(self): def __init__(self):
self.running = False self.running = False
self.coordinates = None self.coordinates = None
self.options = dict()
def on_loaded(self): def on_loaded(self):
logging.info(f"gps plugin loaded for {self.options['device']}") 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.total_messages = 0
self.lock = Lock() self.lock = Lock()
def is_excluded(self, what): def is_excluded(self, what, agent):
for skip in self.options['exclude']: config = agent.config()
for skip in config['main']['whitelist']:
skip = skip.lower() skip = skip.lower()
what = what.lower() what = what.lower()
if skip in what or skip.replace(':', '') in what: if skip in what or skip.replace(':', '') in what:
@ -87,6 +88,7 @@ class Grid(plugins.Plugin):
def check_handshakes(self, agent): def check_handshakes(self, agent):
logging.debug("checking pcaps") logging.debug("checking pcaps")
config = agent.config()
pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap")) pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap"))
num_networks = len(pcap_files) num_networks = len(pcap_files)
@ -98,19 +100,19 @@ class Grid(plugins.Plugin):
if self.options['report']: if self.options['report']:
logging.info("grid: %d new networks to report" % num_new) logging.info("grid: %d new networks to report" % num_new)
logging.debug("self.options: %s" % self.options) 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: for pcap_file in pcap_files:
net_id = os.path.basename(pcap_file).replace('.pcap', '') net_id = os.path.basename(pcap_file).replace('.pcap', '')
if net_id not in reported: 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) logging.debug("skipping %s due to exclusion filter" % pcap_file)
self.set_reported(reported, net_id) self.set_reported(reported, net_id)
continue continue
essid, bssid = parse_pcap(pcap_file) essid, bssid = parse_pcap(pcap_file)
if bssid: 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) logging.debug("not reporting %s due to exclusion filter" % pcap_file)
self.set_reported(reported, net_id) self.set_reported(reported, net_id)
else: 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(): elif ui.is_inky():
h_pos = (140, 68) h_pos = (140, 68)
v_pos = (160, 54) v_pos = (160, 54)
elif ui.is_waveshare27inch(): elif ui.is_waveshare2in7():
h_pos = (192, 138) h_pos = (192, 138)
v_pos = (211, 122) v_pos = (211, 122)
else: else:

View File

@ -24,6 +24,7 @@ class NetPos(plugins.Plugin):
self.skip = list() self.skip = list()
self.ready = False self.ready = False
self.lock = threading.Lock() self.lock = threading.Lock()
self.options = dict()
def on_loaded(self): def on_loaded(self):
if 'api_key' not in self.options or ('api_key' in self.options and not self.options['api_key']): 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.report = StatusFile('/root/.ohc_uploads', data_format='json')
self.skip = list() self.skip = list()
self.lock = Lock() self.lock = Lock()
self.options = dict()
def on_loaded(self): 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") logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
return return
if 'whitelist' not in self.options:
self.options['whitelist'] = list()
self.ready = True self.ready = True
logging.info("OHC: OnlineHashCrack plugin loaded.") logging.info("OHC: OnlineHashCrack plugin loaded.")
def _upload_to_ohc(self, path, timeout=30): def _upload_to_ohc(self, path, timeout=30):
""" """
Uploads the file to onlinehashcrack.com Uploads the file to onlinehashcrack.com
@ -78,7 +75,6 @@ class OnlineHashCrack(plugins.Plugin):
except OSError as os_e: except OSError as os_e:
raise os_e raise os_e
def on_webhook(self, path, request): def on_webhook(self, path, request):
import requests import requests
from flask import redirect 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': ''}) r = s.post('https://www.onlinehashcrack.com/dashboard', data={'emailTasks': self.options['email'], 'submit': ''})
return redirect(r.url, code=302) return redirect(r.url, code=302)
def on_internet_available(self, agent): def on_internet_available(self, agent):
""" """
Called in manual mode when there's internet connectivity 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 handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if
filename.endswith('.pcap')] filename.endswith('.pcap')]
# pull out whitelisted APs # 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) handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
if handshake_new: if handshake_new:
logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onlinehashcrack.com") 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 # 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 # Now, install this plugin by copying this to the 'available-plugins' folder in your pwnagotchi, install and enable the plugin with the commands:
# https://www.ebay.de/itm/For-Raspberry-Pi-Zero-Ups-Power-Expansion-Board-with-Integrated-Serial-Port-S3U4/323873804310 # sudo pwnagotchi plugins install upslite_plugin_1_3
# https://www.aliexpress.com/item/32888533624.html # 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 logging
import struct import struct
@ -20,6 +26,11 @@ import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.components import LabeledValue from pwnagotchi.ui.components import LabeledValue
from pwnagotchi.ui.view import BLACK 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 # TODO: add enable switch in config.yml an cleanup all to the best place
class UPS: class UPS:
@ -31,8 +42,7 @@ class UPS:
def voltage(self): def voltage(self):
try: try:
address = 0x36 read = self._bus.read_word_data(CW2015_ADDRESS, CW2015_REG_VCELL)
read = self._bus.read_word_data(address, 2)
swapped = struct.unpack("<H", struct.pack(">H", read))[0] swapped = struct.unpack("<H", struct.pack(">H", read))[0]
return swapped * 1.25 / 1000 / 16 return swapped * 1.25 / 1000 / 16
except: except:
@ -41,7 +51,7 @@ class UPS:
def capacity(self): def capacity(self):
try: try:
address = 0x36 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] swapped = struct.unpack("<H", struct.pack(">H", read))[0]
return swapped / 256 return swapped / 256
except: except:
@ -57,10 +67,10 @@ class UPS:
class UPSLite(plugins.Plugin): class UPSLite(plugins.Plugin):
__author__ = 'evilsocket@gmail.com' __author__ = 'marbasec'
__version__ = '1.0.0' __version__ = '1.3.0'
__license__ = 'GPL3' __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): def __init__(self):
self.ups = None self.ups = None
@ -69,7 +79,7 @@ class UPSLite(plugins.Plugin):
self.ups = UPS() self.ups = UPS()
def on_ui_setup(self, ui): 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)) label_font=fonts.Bold, text_font=fonts.Medium))
def on_unload(self, ui): def on_unload(self, ui):
@ -80,7 +90,3 @@ class UPSLite(plugins.Plugin):
capacity = self.ups.capacity() capacity = self.ups.capacity()
charging = self.ups.charging() charging = self.ups.charging()
ui.set('ups', "%2i%s" % (capacity, 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 pwnagotchi.plugins as plugins
import logging import logging
import os import os
import json import json
import re import re
import datetime
from flask import Response from flask import Response
from functools import lru_cache from functools import lru_cache
from dateutil.parser import parse from dateutil.parser import parse
@ -22,6 +23,7 @@ from dateutil.parser import parse
''' '''
class Webgpsmap(plugins.Plugin): class Webgpsmap(plugins.Plugin):
__author__ = 'https://github.com/xenDE and https://github.com/dadav' __author__ = 'https://github.com/xenDE and https://github.com/dadav'
__version__ = '1.4.0' __version__ = '1.4.0'
@ -103,7 +105,7 @@ class Webgpsmap(plugins.Plugin):
response_status = 200 response_status = 200
response_mimetype = "application/xhtml+xml" response_mimetype = "application/xhtml+xml"
response_header_contenttype = 'text/html' response_header_contenttype = 'text/html'
response_header_contentdisposition = 'attachment; filename=webgpsmap.html'; response_header_contentdisposition = 'attachment; filename=webgpsmap.html'
except Exception as error: except Exception as error:
logging.error(f"[webgpsmap] on_webhook offlinemap: error: {error}") logging.error(f"[webgpsmap] on_webhook offlinemap: error: {error}")
return return
@ -149,7 +151,6 @@ class Webgpsmap(plugins.Plugin):
def _get_pos_from_file(self, path): def _get_pos_from_file(self, path):
return PositionFile(path) return PositionFile(path)
def load_gps_from_dir(self, gpsdir, newest_only=False): def load_gps_from_dir(self, gpsdir, newest_only=False):
""" """
Parses the gps-data from disk Parses the gps-data from disk
@ -160,13 +161,9 @@ class Webgpsmap(plugins.Plugin):
logging.info(f"[webgpsmap] scanning {handshake_dir}") logging.info(f"[webgpsmap] scanning {handshake_dir}")
all_files = os.listdir(handshake_dir) all_files = os.listdir(handshake_dir)
#print(all_files) # print(all_files)
all_pcap_files = [os.path.join(handshake_dir, filename) all_pcap_files = [os.path.join(handshake_dir, filename) for filename in all_files if filename.endswith('.pcap')]
for filename in all_files
if filename.endswith('.pcap')
]
all_geo_or_gps_files = [] all_geo_or_gps_files = []
for filename_pcap in all_pcap_files: for filename_pcap in all_pcap_files:
filename_base = filename_pcap[:-5] # remove ".pcap" filename_base = filename_pcap[:-5] # remove ".pcap"
@ -300,7 +297,6 @@ class PositionFile:
return parsed_ssid.groups()[0] return parsed_ssid.groups()[0]
return None return None
def json(self): def json(self):
""" """
returns the parsed json returns the parsed json

View File

@ -3,6 +3,7 @@ import logging
import json import json
import csv import csv
import requests import requests
import pwnagotchi
from io import StringIO from io import StringIO
from datetime import datetime from datetime import datetime
@ -24,7 +25,11 @@ def _extract_gps_data(path):
with open(path, 'r') as json_file: with open(path, 'r') as json_file:
tempJson = json.load(json_file) tempJson = json.load(json_file)
d = datetime.utcfromtimestamp(int(tempJson["ts"])) 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: else:
with open(path, 'r') as json_file: with open(path, 'r') as json_file:
return json.load(json_file) return json.load(json_file)
@ -38,7 +43,7 @@ def _format_auth(data):
out = "" out = ""
for auth in data: for auth in data:
out = f"{out}[{auth}]" out = f"{out}[{auth}]"
return out return [f"{auth}" for auth in data]
def _transform_wigle_entry(gps_data, pcap_data, plugin_version): 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() dummy = StringIO()
# write kismet header # 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( dummy.write(
"WigleWifi-1.4,appRelease={},model=pwnagotchi,release={},device=pwnagotchi,display=kismet,board=kismet,brand=pwnagotchi\n".format(plugin_version, __pwnagotchi_version__)) "MAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type\n")
dummy.write(
"MAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type")
writer = csv.writer(dummy, delimiter=",", quoting=csv.QUOTE_NONE, escapechar="\\") writer = csv.writer(dummy, delimiter=",", quoting=csv.QUOTE_NONE, escapechar="\\")
writer.writerow([ writer.writerow([
@ -64,7 +69,7 @@ def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
gps_data['Latitude'], gps_data['Latitude'],
gps_data['Longitude'], gps_data['Longitude'],
gps_data['Altitude'], gps_data['Altitude'],
0, # accuracy? gps_data['Accuracy'],
'WIFI']) 'WIFI'])
return dummy.getvalue() return dummy.getvalue()
@ -84,7 +89,7 @@ def _send_to_wigle(lines, api_key, donate=True, timeout=30):
headers = {'Authorization': f"Basic {api_key}", headers = {'Authorization': f"Basic {api_key}",
'Accept': 'application/json'} 'Accept': 'application/json'}
data = {'donate': 'on' if donate else 'false'} 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: try:
res = requests.post('https://api.wigle.net/api/v2/file/upload', res = requests.post('https://api.wigle.net/api/v2/file/upload',
data=data, data=data,
@ -99,34 +104,32 @@ def _send_to_wigle(lines, api_key, donate=True, timeout=30):
class Wigle(plugins.Plugin): class Wigle(plugins.Plugin):
__author__ = '33197631+dadav@users.noreply.github.com' __author__ = "Dadav and updated by Jayofelony"
__version__ = '2.0.0' __version__ = "3.0.1"
__license__ = 'GPL3' __license__ = "GPL3"
__description__ = 'This plugin automatically uploads collected wifis to wigle.net' __description__ = "This plugin automatically uploads collected WiFi to wigle.net"
def __init__(self): def __init__(self):
self.ready = False self.ready = False
self.report = StatusFile('/root/.wigle_uploads', data_format='json') self.report = StatusFile('/root/.wigle_uploads', data_format='json')
self.skip = list() self.skip = list()
self.lock = Lock() self.lock = Lock()
self.options = dict()
def on_loaded(self): def on_loaded(self):
if 'api_key' not in self.options or ('api_key' in self.options and self.options['api_key'] is None): 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") logging.debug("WIGLE: api_key isn't set. Can't upload to wigle.net")
return return
if not 'whitelist' in self.options: if 'donate' not in self.options:
self.options['whitelist'] = list() self.options['donate'] = False
if not 'donate' in self.options:
self.options['donate'] = True
self.ready = True self.ready = True
logging.info("WIGLE: ready") logging.info("WIGLE: ready")
def on_internet_available(self, agent): 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(): if not self.ready or self.lock.locked():
return return
@ -140,9 +143,9 @@ class Wigle(plugins.Plugin):
all_files = os.listdir(handshake_dir) all_files = os.listdir(handshake_dir)
all_gps_files = [os.path.join(handshake_dir, filename) all_gps_files = [os.path.join(handshake_dir, filename)
for filename in all_files 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) new_gps_files = set(all_gps_files) - set(reported) - set(self.skip)
if new_gps_files: if new_gps_files:
logging.info("WIGLE: Internet connectivity detected. Uploading new handshakes to wigle.net") 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: for gps_file in new_gps_files:
if gps_file.endswith('.gps.json'): if gps_file.endswith('.gps.json'):
pcap_filename = gps_file.replace('.gps.json', '.pcap') 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'): if gps_file.endswith('.geo.json'):
pcap_filename = gps_file.replace('.geo.json', '.pcap') pcap_filename = gps_file.replace('.geo.json', '.pcap')
if not os.path.exists(pcap_filename): 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.") logging.error("WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured.")
return return
if 'whitelist' not in self.options:
self.options['whitelist'] = list()
self.ready = True self.ready = True
logging.info("WPA_SEC: plugin loaded") logging.info("WPA_SEC: plugin loaded")
@ -101,9 +98,8 @@ class WpaSec(plugins.Plugin):
reported = self.report.data_field_or('reported', default=list()) reported = self.report.data_field_or('reported', default=list())
handshake_dir = config['bettercap']['handshakes'] handshake_dir = config['bettercap']['handshakes']
handshake_filenames = os.listdir(handshake_dir) handshake_filenames = os.listdir(handshake_dir)
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if filename.endswith('.pcap')]
filename.endswith('.pcap')] handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist'])
handshake_paths = remove_whitelisted(handshake_paths, self.options['whitelist'])
handshake_new = set(handshake_paths) - set(reported) - set(self.skip) handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
if handshake_new: if handshake_new:

View File

@ -1 +0,0 @@

View File

@ -103,8 +103,8 @@ class Display(View):
def is_waveshare2in13d(self): def is_waveshare2in13d(self):
return self._implementation.name == 'waveshare2in13d' return self._implementation.name == 'waveshare2in13d'
def is_waveshare2in23g(self): def is_waveshare2in13g(self):
return self._implementation.name == 'waveshare2in23g' return self._implementation.name == 'waveshare2in13g'
def is_waveshare2in36g(self): def is_waveshare2in36g(self):
return self._implementation.name == 'waveshare2in36g' return self._implementation.name == 'waveshare2in36g'
@ -112,6 +112,9 @@ class Display(View):
def is_waveshare2in66(self): def is_waveshare2in66(self):
return self._implementation.name == 'waveshare2in66' return self._implementation.name == 'waveshare2in66'
def is_waveshare2in66b(self):
return self._implementation.name == 'waveshare2in66b'
def is_waveshare2in66g(self): def is_waveshare2in66g(self):
return self._implementation.name == 'waveshare2in66g' 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.waveshare1in54b import Waveshare154inchb
from pwnagotchi.ui.hw.waveshare2in13bc import Waveshare213bc from pwnagotchi.ui.hw.waveshare2in13bc import Waveshare213bc
from pwnagotchi.ui.hw.waveshare2in13d import Waveshare213d 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.waveshare2in13b_V4 import Waveshare213bV4
from pwnagotchi.ui.hw.waveshare3in5lcd import Waveshare35lcd from pwnagotchi.ui.hw.waveshare3in5lcd import Waveshare35lcd
from pwnagotchi.ui.hw.spotpear24in import Spotpear24inch from pwnagotchi.ui.hw.spotpear24in import Spotpear24inch
from pwnagotchi.ui.hw.displayhatmini import DisplayHatMini 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 import Waveshare154
from pwnagotchi.ui.hw.waveshare1in54_V2 import Waveshare154V2 from pwnagotchi.ui.hw.waveshare1in54_V2 import Waveshare154V2
from pwnagotchi.ui.hw.waveshare1in54b_V2 import Waveshare154bV2 from pwnagotchi.ui.hw.waveshare1in54b_V2 import Waveshare154bV2
# from pwnagotchi.ui.hw.waveshare1in54c import Waveshare154c from pwnagotchi.ui.hw.waveshare1in54c import Waveshare1in54c
# from pwnagotchi.ui.hw.waveshare1in64g import Waveshare164g from pwnagotchi.ui.hw.waveshare1in64g import Waveshare1in64g
from pwnagotchi.ui.hw.waveshare2in7b import Waveshare27b from pwnagotchi.ui.hw.waveshare2in7b import Waveshare27b
from pwnagotchi.ui.hw.waveshare2in7b_V2 import Waveshare27bV2 from pwnagotchi.ui.hw.waveshare2in7b_V2 import Waveshare27bV2
from pwnagotchi.ui.hw.waveshare2in9b_V3 import Waveshare29bV3 from pwnagotchi.ui.hw.waveshare2in9b_V3 import Waveshare29bV3
from pwnagotchi.ui.hw.waveshare2in9b_V4 import Waveshare29bV4 from pwnagotchi.ui.hw.waveshare2in9b_V4 import Waveshare29bV4
# from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare29bc from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare2in9bc
# from pwnagotchi.ui.hw.waveshare2in9d import Waveshare29d from pwnagotchi.ui.hw.waveshare2in9d import Waveshare2in9d
from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare213bV3 from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare2in13bV3
# from pwnagotchi.ui.hw.waveshare2in23g import Waveshare223g from pwnagotchi.ui.hw.waveshare2in36g import Waveshare2in36g
# from pwnagotchi.ui.hw.waveshare2in36g import Waveshare236g from pwnagotchi.ui.hw.waveshare2in66 import Waveshare2in66
# from pwnagotchi.ui.hw.waveshare2in66 import Waveshare266 from pwnagotchi.ui.hw.waveshare2in66b import Waveshare2in66b
# from pwnagotchi.ui.hw.waveshare3in0g import Waveshare30g from pwnagotchi.ui.hw.waveshare2in66g import Waveshare2in66g
# from pwnagotchi.ui.hw.waveshare3in7 import Waveshare37 from pwnagotchi.ui.hw.waveshare3in0g import Waveshare3in0g
# from pwnagotchi.ui.hw.waveshare3in52 import Waveshare352 from pwnagotchi.ui.hw.waveshare3in7 import Waveshare3in7
# from pwnagotchi.ui.hw.waveshare4in01f import Waveshare401f from pwnagotchi.ui.hw.waveshare3in52 import Waveshare3in52
# from pwnagotchi.ui.hw.waveshare4in2 import Waveshare42inch from pwnagotchi.ui.hw.waveshare4in01f import Waveshare4in01f
# from pwnagotchi.ui.hw.waveshare4in2_V2 import Waveshare42V2 from pwnagotchi.ui.hw.waveshare4in2 import Waveshare4in2
# from pwnagotchi.ui.hw.waveshare4in2b_V2 import Waveshare42bV2 from pwnagotchi.ui.hw.waveshare4in2_V2 import Waveshare4in2V2
# from pwnagotchi.ui.hw.waveshare4in2bc import Waveshare42bc from pwnagotchi.ui.hw.waveshare4in2b_V2 import Waveshare4in2bV2
# from pwnagotchi.ui.hw.waveshare4in26 import Waveshare426 from pwnagotchi.ui.hw.waveshare4in2bc import Waveshare4in2bc
# from pwnagotchi.ui.hw.waveshare4in37g import Waveshare437g from pwnagotchi.ui.hw.waveshare4in26 import Waveshare4in26
# from pwnagotchi.ui.hw.waveshare5in65f import Waveshare565f from pwnagotchi.ui.hw.waveshare4in37g import Waveshare4in37g
# from pwnagotchi.ui.hw.waveshare5in83 import Waveshare583 from pwnagotchi.ui.hw.waveshare5in65f import Waveshare5in65f
# from pwnagotchi.ui.hw.waveshare5in83_V2 import Waveshare583V2 from pwnagotchi.ui.hw.waveshare5in83 import Waveshare5in83
# from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare583bV2 from pwnagotchi.ui.hw.waveshare5in83_V2 import Waveshare5in83V2
# from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare583bc from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare5in83bV2
# from pwnagotchi.ui.hw.waveshare7in3f import Waveshare73f from pwnagotchi.ui.hw.waveshare5in83bc import Waveshare5in83bc
# from pwnagotchi.ui.hw.waveshare7in3g import Waveshare73g from pwnagotchi.ui.hw.waveshare7in3f import Waveshare7in3f
# from pwnagotchi.ui.hw.waveshare7in5 import Waveshare75 from pwnagotchi.ui.hw.waveshare7in3g import Waveshare7in3g
# from pwnagotchi.ui.hw.waveshare7in5_HD import Waveshare75HD from pwnagotchi.ui.hw.waveshare7in5 import Waveshare7in5
# from pwnagotchi.ui.hw.waveshare7in5_V2 import Waveshare75V2 from pwnagotchi.ui.hw.waveshare7in5_HD import Waveshare7in5HD
# from pwnagotchi.ui.hw.waveshare7in5b_HD import Waveshare75bHD from pwnagotchi.ui.hw.waveshare7in5_V2 import Waveshare7in5V2
# from pwnagotchi.ui.hw.waveshare7in5b_V2 import Waveshare75bV2 from pwnagotchi.ui.hw.waveshare7in5b_HD import Waveshare7in5bHD
# from pwnagotchi.ui.hw.waveshare7in5bc import Waveshare75bc from pwnagotchi.ui.hw.waveshare7in5b_V2 import Waveshare7in5bV2
# from pwnagotchi.ui.hw.waveshare13in3k import Waveshare133k from pwnagotchi.ui.hw.waveshare7in5bc import Waveshare7in5bc
from pwnagotchi.ui.hw.waveshare13in3k import Waveshare13in3k
def display_for(config): def display_for(config):
@ -82,6 +84,21 @@ def display_for(config):
elif config['ui']['display']['type'] == 'dfrobot_2': elif config['ui']['display']['type'] == 'dfrobot_2':
return DFRobotV2(config) 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': elif config['ui']['display']['type'] == 'waveshare1in54':
return Waveshare154(config) return Waveshare154(config)
@ -94,12 +111,36 @@ def display_for(config):
elif config['ui']['display']['type'] == 'waveshare1in54b_v2': elif config['ui']['display']['type'] == 'waveshare1in54b_v2':
return Waveshare154bV2(config) 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': elif config['ui']['display']['type'] == 'waveshare2in7b':
return Waveshare27b(config) return Waveshare27b(config)
elif config['ui']['display']['type'] == 'waveshare2in7b_v2': elif config['ui']['display']['type'] == 'waveshare2in7b_v2':
return Waveshare27bV2(config) 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': elif config['ui']['display']['type'] == 'waveshare2in9b_v3':
return Waveshare29bV3(config) return Waveshare29bV3(config)
@ -118,137 +159,101 @@ def display_for(config):
elif config['ui']['display']['type'] == 'waveshare_4': elif config['ui']['display']['type'] == 'waveshare_4':
return WaveshareV4(config) 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': elif config['ui']['display']['type'] == 'waveshare2in13bc':
return Waveshare213bc(config) return Waveshare213bc(config)
elif config['ui']['display']['type'] == 'waveshare2in13d': elif config['ui']['display']['type'] == 'waveshare2in13d':
return Waveshare213d(config) return Waveshare213d(config)
elif config['ui']['display']['type'] == 'waveshare2in13b_v3':
return Waveshare2in13bV3(config)
elif config['ui']['display']['type'] == 'waveshare2in13b_v4': elif config['ui']['display']['type'] == 'waveshare2in13b_v4':
return Waveshare213bV4(config) return Waveshare213bV4(config)
elif config['ui']['display']['type'] == 'waveshare35lcd': elif config['ui']['display']['type'] == 'waveshare2in13g':
return Waveshare35lcd(config) return Waveshare2in13g(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'] == 'waveshare2in36g': elif config['ui']['display']['type'] == 'waveshare2in36g':
return return Waveshare2in36g(config)
elif config['ui']['display']['type'] == 'waveshare2in66': 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': elif config['ui']['display']['type'] == 'waveshare3in0g':
return return Waveshare3in0g(config)
elif config['ui']['display']['type'] == 'waveshare3in7': elif config['ui']['display']['type'] == 'waveshare3in7':
return return Waveshare3in7(config)
elif config['ui']['display']['type'] == 'waveshare3in52': elif config['ui']['display']['type'] == 'waveshare3in52':
return return Waveshare3in52(config)
elif config['ui']['display']['type'] == 'waveshare4in01f': elif config['ui']['display']['type'] == 'waveshare4in01f':
return return Waveshare4in01f(config)
elif config['ui']['display']['type'] == 'waveshare4in2': elif config['ui']['display']['type'] == 'waveshare4in2':
return return Waveshare4in2(config)
elif config['ui']['display']['type'] == 'waveshare4in2_v2': elif config['ui']['display']['type'] == 'waveshare4in2_v2':
return return Waveshare4in2V2(config)
elif config['ui']['display']['type'] == 'waveshare4in2b_v2': elif config['ui']['display']['type'] == 'waveshare4in2b_v2':
return return Waveshare4in2bV2(config)
elif config['ui']['display']['type'] == 'waveshare4in2bc': elif config['ui']['display']['type'] == 'waveshare4in2bc':
return return Waveshare4in2bc(config)
elif config['ui']['display']['type'] == 'waveshare4in26': elif config['ui']['display']['type'] == 'waveshare4in26':
return return Waveshare4in26(config)
elif config['ui']['display']['type'] == 'waveshare4in37g': elif config['ui']['display']['type'] == 'waveshare4in37g':
return return Waveshare4in37g(config)
elif config['ui']['display']['type'] == 'waveshare5in65f': elif config['ui']['display']['type'] == 'waveshare5in65f':
return return Waveshare5in65f(config)
elif config['ui']['display']['type'] == 'waveshare5in83': elif config['ui']['display']['type'] == 'waveshare5in83':
return return Waveshare5in83(config)
elif config['ui']['display']['type'] == 'waveshare5in83_v2': elif config['ui']['display']['type'] == 'waveshare5in83_v2':
return return Waveshare5in83V2(config)
elif config['ui']['display']['type'] == 'waveshare5in83b_v2': elif config['ui']['display']['type'] == 'waveshare5in83b_v2':
return return Waveshare5in83bV2(config)
elif config['ui']['display']['type'] == 'waveshare5in83bc': elif config['ui']['display']['type'] == 'waveshare5in83bc':
return return Waveshare5in83bc(config)
elif config['ui']['display']['type'] == 'waveshare7in3f': elif config['ui']['display']['type'] == 'waveshare7in3f':
return return Waveshare7in3f(config)
elif config['ui']['display']['type'] == 'waveshare7in3g': elif config['ui']['display']['type'] == 'waveshare7in3g':
return return Waveshare7in3g(config)
elif config['ui']['display']['type'] == 'waveshare7in5': elif config['ui']['display']['type'] == 'waveshare7in5':
return return Waveshare7in5(config)
elif config['ui']['display']['type'] == 'waveshare7in5_HD': elif config['ui']['display']['type'] == 'waveshare7in5_HD':
return return Waveshare7in5HD(config)
elif config['ui']['display']['type'] == 'waveshare7in5_v2': elif config['ui']['display']['type'] == 'waveshare7in5_v2':
return return Waveshare7in5V2(config)
elif config['ui']['display']['type'] == 'waveshare7in5b_HD': elif config['ui']['display']['type'] == 'waveshare7in5b_HD':
return return Waveshare7in5bHD(config)
elif config['ui']['display']['type'] == 'waveshare7in5b_v2': elif config['ui']['display']['type'] == 'waveshare7in5b_v2':
return return Waveshare7in5bV2(config)
elif config['ui']['display']['type'] == 'waveshare7in5bc': elif config['ui']['display']['type'] == 'waveshare7in5bc':
return return Waveshare7in5bc(config)
elif config['ui']['display']['type'] == 'waveshare13in3k': 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): class DisplayImpl(object):
def __init__(self, config, name): def __init__(self, config, name):
self._display = None
if fonts.Medium is None: if fonts.Medium is None:
fonts.init(config) fonts.init(config)
self.name = name self.name = name

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,11 +2,12 @@ from . import SH1106
from . import config from . import config
# Display resolution # Display resolution
EPD_WIDTH = 64 EPD_WIDTH = 64
EPD_HEIGHT = 128 EPD_HEIGHT = 128
disp = SH1106.SH1106() disp = SH1106.SH1106()
class EPD(object): class EPD(object):
def __init__(self): 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): def display(self, image):
if (image == None): if (image == None):
return 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): if (self.width % 8 == 0):
Width = self.width / 8 Width = self.width // 8
else: else:
Width = self.width / 8 + 1 Width = self.width // 8 + 1
self.send_command(0x10) self.send_command(0x10)
for j in range(0, self.height): for j in range(0, self.height):
@ -282,11 +282,11 @@ class EPD:
self.TurnOnDisplay() self.TurnOnDisplay()
def Clear(self): 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): if (self.width % 8 == 0):
Width = self.width / 8 Width = self.width // 8
else: else:
Width = self.width / 8 + 1 Width = self.width // 8 + 1
Height = self.height Height = self.height
@ -313,11 +313,11 @@ class EPD:
self.send_data(127) # y-end self.send_data(127) # y-end
self.send_data(0x00) 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): if (self.width % 8 == 0):
Width = self.width / 8 Width = self.width // 8
else: else:
Width = self.width / 8 + 1 Width = self.width // 8 + 1
Height = self.height Height = self.height
# send data # send data

View File

@ -169,7 +169,7 @@ class EPD:
# self.ReadBusy() # self.ReadBusy()
def init(self, lut): def init(self, lut):
if (epdconfig.module_init() != 0): if epdconfig.module_init() != 0:
return -1 return -1
# EPD hardware init start # EPD hardware init start
self.reset() 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): def SetWindow(self):
self.send_command(0x61) # SET_RAM_X_ADDRESS_START_END_POSITION 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 # 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.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) self.send_data(self.Gate_BITS % 256)
def TurnOnDisplay(self): def TurnOnDisplay(self):
@ -166,20 +166,21 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
# Create a pallette with the 4 colors supported by the panel # Create a pallette with the 4 colors supported by the panel
global image_temp
pal_image = Image.new("P", (1, 1)) 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) 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 # Check if we need to rotate the image
imwidth, imheight = image.size imwidth, imheight = image.size
if (imwidth == self.width and imheight == self.height): if imwidth == self.width and imheight == self.height:
image_temp = image 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) image_temp = image.rotate(90, expand=True)
else: else:
logger.warning( logger.warning(
"Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) "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) image_4color = image_temp.convert("RGB").quantize(palette=pal_image)
buf_4color = bytearray(image_4color.tobytes('raw')) buf_4color = bytearray(image_4color.tobytes('raw'))

View File

@ -1,11 +1,11 @@
# ***************************************************************************** # *****************************************************************************
# * | File : epd2in13b_V4.py # * | File : epd2in66b.py
# * | Author : Waveshare team # * | Author : Waveshare team
# * | Function : Electronic paper driver # * | Function : Electronic paper driver
# * | Info : # * | Info :
# *---------------- # *----------------
# * | This version: V1.0 # * | This version: V1.1
# * | Date : 2022-04-21 # * | Date : 2022-08-9
# # | Info : python demo # # | Info : python demo
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
@ -28,11 +28,11 @@
# #
import logging import logging
from . import epdconfig from .. import epdconfig
# Display resolution # Display resolution
EPD_WIDTH = 122 EPD_WIDTH = 152
EPD_HEIGHT = 250 EPD_HEIGHT = 296
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -46,23 +46,21 @@ class EPD:
self.width = EPD_WIDTH self.width = EPD_WIDTH
self.height = EPD_HEIGHT self.height = EPD_HEIGHT
# hardware reset # Hardware reset
def reset(self): def reset(self):
epdconfig.digital_write(self.reset_pin, 1) epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(20) epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0) epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(2) epdconfig.delay_ms(5)
epdconfig.digital_write(self.reset_pin, 1) epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(20) epdconfig.delay_ms(200)
# send 1 byte command
def send_command(self, command): def send_command(self, command):
epdconfig.digital_write(self.dc_pin, 0) epdconfig.digital_write(self.dc_pin, 0)
epdconfig.digital_write(self.cs_pin, 0) epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([command]) epdconfig.spi_writebyte([command])
epdconfig.digital_write(self.cs_pin, 1) epdconfig.digital_write(self.cs_pin, 1)
# send 1 byte data
def send_data(self, data): def send_data(self, data):
epdconfig.digital_write(self.dc_pin, 1) epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0) epdconfig.digital_write(self.cs_pin, 0)
@ -76,129 +74,116 @@ class EPD:
epdconfig.spi_writebyte2(data) epdconfig.spi_writebyte2(data)
epdconfig.digital_write(self.cs_pin, 1) epdconfig.digital_write(self.cs_pin, 1)
# judge e-Paper whether is busy def ReadBusy(self):
def busy(self):
logger.debug("e-Paper busy") logger.debug("e-Paper busy")
while (epdconfig.digital_read(self.busy_pin) != 0): while (epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(10) epdconfig.delay_ms(20)
logger.debug("e-Paper busy release") 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): def init(self):
if (epdconfig.module_init() != 0): if (epdconfig.module_init() != 0):
return -1 return -1
# EPD hardware init start
self.reset() self.reset()
self.busy() self.send_command(0x12)
self.send_command(0x12) # SWRESET epdconfig.delay_ms(30)
self.busy() self.ReadBusy()
self.send_command(0x01) # Driver output control self.send_command(0x11) # setting gaet number
self.send_data(0xf9)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x11) # data entry mode
self.send_data(0x03) self.send_data(0x03)
self.set_windows(0, 0, self.width - 1, self.height - 1) self.setWindows(0, 0, self.width - 1, self.height - 1)
self.set_cursor(0, 0)
self.send_command(0x3C) # BorderWavefrom self.send_command(0x21)
self.send_data(0x05) self.send_data(0x00)
self.send_command(0x18) # Read built-in temperature sensor
self.send_data(0x80) self.send_data(0x80)
self.send_command(0x21) # Display update control self.setCursor(0, 0)
self.send_data(0x80) self.ReadBusy()
self.send_data(0x80)
self.busy()
return 0 return 0
# turn on display def setWindows(self, Xstart, Ystart, Xend, Yend):
def ondisplay(self): 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.send_command(0x20)
self.busy() self.ReadBusy()
# image converted to bytearray
def getbuffer(self, image): def getbuffer(self, image):
img = image # logger.debug("bufsiz = ",int(self.width/8) * self.height)
imwidth, imheight = img.size 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): 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): elif (imwidth == self.height and imheight == self.width):
# image has correct dimensions, but needs to be rotated logger.debug("Horizontal")
img = img.rotate(90, expand=True).convert('1') for y in range(imheight):
else: for x in range(imwidth):
logger.warning("Wrong image dimensions: must be " + newx = y
str(self.width) + "x" + str(self.height)) newy = self.height - x - 1
# return a blank buffer if pixels[x, y] == 0:
return [0x00] * (int(self.width/8) * self.height) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
buf = bytearray(img.tobytes('raw'))
return buf return buf
# display image def display(self, Blackimage, Redimage):
def display(self, imageblack, imagered): 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_command(0x24)
self.send_data2(imageblack) self.send_data2(Blackimage)
self.send_command(0x26) 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): 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): def sleep(self):
self.send_command(0x10) # DEEP_SLEEP self.send_command(0X10) # DEEP_SLEEP_MODE
self.send_data(0x01) # check code self.send_data(0x01)
epdconfig.delay_ms(2000) epdconfig.delay_ms(2000)
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,11 @@
# ***************************************************************************** # *****************************************************************************
# * | File : epd7in5.py # * | File : epd4in26.py
# * | Author : Waveshare team # * | Author : Waveshare team
# * | Function : Electronic paper driver # * | Function : Electronic paper driver
# * | Info : # * | Info :
# *---------------- # *----------------
# * | This version: V4.0 # * | This version: V1.0
# * | Date : 2019-06-20 # * | Date : 2023-12-20
# # | Info : python demo # # | Info : python demo
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
@ -29,11 +29,16 @@
import logging import logging
from .. import epdconfig from . import epdconfig
# Display resolution # Display resolution
EPD_WIDTH = 880 EPD_WIDTH = 800
EPD_HEIGHT = 528 EPD_HEIGHT = 480
GRAY1 = 0xff # white
GRAY2 = 0xC0
GRAY3 = 0x80 # gray
GRAY4 = 0x00 # Blackest
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -46,15 +51,39 @@ class EPD:
self.cs_pin = epdconfig.CS_PIN self.cs_pin = epdconfig.CS_PIN
self.width = EPD_WIDTH self.width = EPD_WIDTH
self.height = EPD_HEIGHT 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 # Hardware reset
def reset(self): def reset(self):
epdconfig.digital_write(self.reset_pin, 1) epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200) epdconfig.delay_ms(20)
epdconfig.digital_write(self.reset_pin, 0) epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(2) epdconfig.delay_ms(2)
epdconfig.digital_write(self.reset_pin, 1) epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200) epdconfig.delay_ms(20)
def send_command(self, command): def send_command(self, command):
epdconfig.digital_write(self.dc_pin, 0) epdconfig.digital_write(self.dc_pin, 0)
@ -71,7 +100,7 @@ class EPD:
def send_data2(self, data): def send_data2(self, data):
epdconfig.digital_write(self.dc_pin, 1) epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0) epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte2(data) epdconfig.SPI.writebytes2(data)
epdconfig.digital_write(self.cs_pin, 1) epdconfig.digital_write(self.cs_pin, 1)
def ReadBusy(self): def ReadBusy(self):
@ -79,102 +108,408 @@ class EPD:
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
while (busy == 1): while (busy == 1):
busy = epdconfig.digital_read(self.busy_pin) 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): def init(self):
if (epdconfig.module_init() != 0): if (epdconfig.module_init() != 0):
return -1 return -1
# EPD hardware init start # EPD hardware init start
self.reset() self.reset()
self.ReadBusy()
self.ReadBusy(); self.send_command(0x12) # SWRESET
self.send_command(0x12); # SWRESET self.ReadBusy()
self.ReadBusy();
self.send_command(0x46); # Auto Write Red RAM self.send_command(0x18) # use the internal temperature sensor
self.send_data(0xf7); self.send_data(0x80)
self.ReadBusy();
self.send_command(0x47); # Auto Write B/W RAM
self.send_data(0xf7);
self.ReadBusy();
self.send_command(0x0C); # Soft start setting self.send_command(0x0C) # set soft start
self.send_data2([0xAE, 0xC7, 0xC3, 0xC0, 0x40]) 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_command(0x01) # drive output control
self.send_data2([0xAF, 0x02, 0x01]) 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_command(0x3C) # Border Border setting
self.send_data(0x01); self.send_data(0x01)
self.send_command(0x44); self.send_command(0x11) # data entry mode
self.send_data2([0x00, 0x00, 0x6F, 0x03]) # RAM x address start at 0 self.send_data(0x01) # X-mode x+ y-
self.send_command(0x45);
self.send_data2([0xAF, 0x02, 0x00, 0x00])
self.send_command(0x3C); # VBD self.SetWindow(0, self.height - 1, self.width - 1, 0)
self.send_data(0x05); # LUT1, for white
self.send_command(0x18); self.SetCursor(0, 0)
self.send_data(0X80); self.ReadBusy()
self.send_command(0x22); # EPD hardware init end
self.send_data(0XB1); # Load Temperature and waveform setting. return 0
self.send_command(0x20);
self.ReadBusy();
self.send_command(0x4E); # set RAM x address count to 0; def init_Fast(self):
self.send_data2([0x00, 0x00]) if (epdconfig.module_init() != 0):
self.send_command(0x4F); return -1
self.send_data2([0x00, 0x00]) # 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 # EPD hardware init end
return 0 return 0
def getbuffer(self, image): def getbuffer(self, image):
img = image # logger.debug("bufsiz = ",int(self.width/8) * self.height)
imwidth, imheight = img.size buf = [0xFF] * (int(self.width / 8) * self.height)
if (imwidth == self.width and imheight == self.height): image_monocolor = image.convert('1')
img = img.convert('1') imwidth, imheight = image_monocolor.size
elif (imwidth == self.height and imheight == self.width): pixels = image_monocolor.load()
img = img.rotate(90, expand=True).convert('1') # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight)
else: if imwidth == self.width and imheight == self.height:
logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) logger.debug("Horizontal")
# return a blank buffer for y in range(imheight):
return [0xff] * int(self.width * self.height / 8) 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 return buf
def display(self, image): 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_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_command(0x26)
self.send_data2(buf) self.send_data2(image)
self.send_command(0x22); self.TurnOnDisplay()
self.send_data(0xF7); # Load LUT from MCU(0x32)
self.send_command(0x20); def display_Fast(self, image):
epdconfig.delay_ms(10); self.send_command(0x24)
self.ReadBusy(); 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): def sleep(self):
self.send_command(0x10); self.send_command(0x10) # DEEP_SLEEP
self.send_data(0x01); self.send_data(0x01)
epdconfig.delay_ms(2000) epdconfig.delay_ms(2000)
epdconfig.module_exit() epdconfig.module_exit()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,12 +3,12 @@ import logging
import pwnagotchi.ui.fonts as fonts import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl from pwnagotchi.ui.hw.base import DisplayImpl
import os,time import time
class Spotpear24inch(DisplayImpl): class Spotpear24inch(DisplayImpl):
def __init__(self, config): def __init__(self, config):
super(Spotpear24inch, self).__init__(config, 'spotpear24inch') super(Spotpear24inch, self).__init__(config, 'spotpear24inch')
self._display = None
def layout(self): def layout(self):
fonts.setup(12, 10, 12, 70, 25, 9) 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,44 @@
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):
self._display.display(canvas)
def clear(self):
self._display.Clear()

View File

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

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare144lcd(DisplayImpl): class Waveshare144lcd(DisplayImpl):
def __init__(self, config): def __init__(self, config):
super(Waveshare144lcd, self).__init__(config, 'waveshare144lcd') super(Waveshare144lcd, self).__init__(config, 'waveshare144lcd')
self._display = None
def layout(self): def layout(self):
fonts.setup(10, 8, 10, 18, 25, 9) fonts.setup(10, 8, 10, 18, 25, 9)
@ -42,5 +41,4 @@ class Waveshare144lcd(DisplayImpl):
self._display.display(canvas) self._display.display(canvas)
def clear(self): 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): class Waveshare154(DisplayImpl):
def __init__(self, config): def __init__(self, config):
super(Waveshare154, self).__init__(config, 'waveshare1in54') super(Waveshare154, self).__init__(config, 'waveshare1in54')
self._display = None
def layout(self): def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9) fonts.setup(10, 9, 10, 35, 25, 9)
@ -32,10 +31,10 @@ class Waveshare154(DisplayImpl):
return self._layout return self._layout
def initialize(self): 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 from pwnagotchi.ui.hw.libs.waveshare.v1in54.epd1in54 import EPD
self._display = EPD() self._display = EPD()
self._display.init() self._display.init(0x00)
self._display.Clear() self._display.Clear()
def render(self, canvas): def render(self, canvas):
@ -43,4 +42,5 @@ class Waveshare154(DisplayImpl):
self._display.display(buf, None) self._display.display(buf, None)
def clear(self): def clear(self):
# pass
self._display.Clear() self._display.Clear()

View File

@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare154V2(DisplayImpl): class Waveshare154V2(DisplayImpl):
def __init__(self, config): def __init__(self, config):
super(Waveshare154V2, self).__init__(config, 'waveshare1in54_v2') super(Waveshare154V2, self).__init__(config, 'waveshare1in54_v2')
self._display = None
def layout(self): def layout(self):
fonts.setup(10, 9, 10, 35, 25, 9) fonts.setup(10, 9, 10, 35, 25, 9)
@ -32,10 +31,10 @@ class Waveshare154V2(DisplayImpl):
return self._layout return self._layout
def initialize(self): def initialize(self):
logging.info("initializing waveshare v154 display") logging.info("initializing waveshare v1in54_v2 display")
from pwnagotchi.ui.hw.libs.waveshare.v1in54_v2.epd1in54_V2 import EPD from pwnagotchi.ui.hw.libs.waveshare.v1in54_v2.epd1in54_V2 import EPD
self._display = EPD() self._display = EPD()
self._display.init() self._display.init(False)
self._display.Clear() self._display.Clear()
def render(self, canvas): def render(self, canvas):

View File

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

View File

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

View File

@ -0,0 +1,44 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare1in54c(DisplayImpl):
def __init__(self, config):
super(Waveshare1in54c, self).__init__(config, 'waveshare1in54c')
def layout(self):
fonts.setup(10, 8, 10, 18, 25, 9)
self._layout['width'] = 152
self._layout['height'] = 152
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, 152, 12]
self._layout['line2'] = [0, 116, 152, 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.54c inch lcd display")
from pwnagotchi.ui.hw.libs.waveshare.v1in54c.epd1in54c import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
self._display.display(canvas)
def clear(self):
self._display.Clear()

View File

@ -0,0 +1,44 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare1in64g(DisplayImpl):
def __init__(self, config):
super(Waveshare1in64g, self).__init__(config, 'waveshare1in64g')
def layout(self):
fonts.setup(10, 8, 10, 18, 25, 9)
self._layout['width'] = 168
self._layout['height'] = 168
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, 168, 12]
self._layout['line2'] = [0, 116, 168, 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.64g inch lcd display")
from pwnagotchi.ui.hw.libs.waveshare.v1in64g.epd1in64g import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
self._display.display(canvas)
def clear(self):
self._display.Clear()

View File

@ -1,69 +0,0 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class WaveshareV2(DisplayImpl):
def __init__(self, config):
super(WaveshareV2, self).__init__(config, 'waveshare_2')
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['status'] = (91, 15)
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': (125, 20),
'font': fonts.status_font(fonts.Medium),
'max': 14
}
return self._layout
def initialize(self):
logging.info("initializing waveshare v2 display")
from pwnagotchi.ui.hw.libs.waveshare.v2.waveshare import EPD
self._display = EPD()
self._display.init(self._display.FULL_UPDATE)
self._display.Clear(0xff)
self._display.init(self._display.PART_UPDATE)
def render(self, canvas):
buf = self._display.getbuffer(canvas)
self._display.displayPartial(buf)
def clear(self):
self._display.Clear(0xff)

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