mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
Compare commits
92 Commits
Author | SHA1 | Date | |
---|---|---|---|
1780859889 | |||
fdd98bb37a | |||
7530709d0c | |||
a9a6fd424b | |||
8c97301992 | |||
91eaa22188 | |||
31a4af4c21 | |||
dceeaff1fb | |||
c0241dc8df | |||
8f405f4ab2 | |||
bd79e71563 | |||
7f662585aa | |||
d23ff8d47a | |||
04435229fe | |||
42e236bafe | |||
5081b72695 | |||
652740f050 | |||
1b6b12bdf5 | |||
c610335a34 | |||
6c39ed97dd | |||
967f1663c6 | |||
ffe1e90ccd | |||
f2d2bcbfdf | |||
bfc0795fb8 | |||
1a55afd74a | |||
1594e7c129 | |||
a244e70a1c | |||
d35d5d6c3c | |||
7aacf9fb44 | |||
dde6fa4c2a | |||
7dfb2f2ff6 | |||
cf46ab3da9 | |||
6824e541a4 | |||
1c4e8fa750 | |||
a50ec4a65c | |||
5414fdf21d | |||
c9883bb4f9 | |||
045f5853bc | |||
6dfcaf05d5 | |||
e2f8119d2c | |||
d675b3d0dd | |||
30850b6530 | |||
1e9c9bae42 | |||
64241515ad | |||
c9f232dae2 | |||
4f97bcaa83 | |||
7d2a03c79f | |||
f89ba85f73 | |||
57f03f4359 | |||
9bc266f9ff | |||
b0db0285bc | |||
cca3e77d50 | |||
4fe603bf5e | |||
9a9ee70a78 | |||
7fc8838f76 | |||
94b2ff7047 | |||
8edb0fdaa4 | |||
b557768159 | |||
5a6967eb4d | |||
c0c35231cf | |||
88362b3354 | |||
e50cf04967 | |||
85a64a3914 | |||
63d0c20a3e | |||
044639a6d4 | |||
7fc2c6b25f | |||
c5d5d9bb14 | |||
129ae92447 | |||
2560692ee2 | |||
1424e0d510 | |||
2c9eaa436a | |||
0c5c6058a5 | |||
a3fb39d78c | |||
bac62bc4aa | |||
f7a5f2a554 | |||
6921fd14a3 | |||
0dbd611ed5 | |||
18b9093f70 | |||
26913016b9 | |||
0786b6757e | |||
0f4eda8039 | |||
1672a35f09 | |||
80e7e6c550 | |||
ca274036ab | |||
649e8a4222 | |||
63f0a761c1 | |||
8a64918b55 | |||
c27cc0ac24 | |||
c9bdce0ea3 | |||
6422371346 | |||
3c5a95e0b8 | |||
18217119fc |
21
.idea/deployment.xml
generated
21
.idea/deployment.xml
generated
@ -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
3
.idea/misc.xml
generated
@ -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>
|
@ -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’.
|
||||||
|
@ -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
1
apt_packages.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
hcxtools
|
@ -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)
|
||||||
|
15
builder/data/etc/default/zramswap
Normal file
15
builder/data/etc/default/zramswap
Normal 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
|
@ -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
|
|
@ -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/"
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = '2.6.8'
|
__version__ = '2.8.0'
|
||||||
|
@ -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']
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
Binary file not shown.
@ -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"
|
||||||
|
Binary file not shown.
@ -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 "שניה"
|
Binary file not shown.
@ -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"
|
||||||
|
BIN
pwnagotchi/locale/pt-br/LC_MESSAGES/voice.mo
Normal file
BIN
pwnagotchi/locale/pt-br/LC_MESSAGES/voice.mo
Normal file
Binary file not shown.
@ -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"
|
@ -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"
|
||||||
|
73
pwnagotchi/plugins/default/aircrackonly.py
Normal file
73
pwnagotchi/plugins/default/aircrackonly.py
Normal 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 = ""
|
@ -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")
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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 ...'})
|
||||||
|
@ -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']}")
|
||||||
|
@ -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:
|
||||||
|
179
pwnagotchi/plugins/default/hashie.py
Normal file
179
pwnagotchi/plugins/default/hashie.py
Normal 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)))
|
@ -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:
|
||||||
|
@ -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']):
|
||||||
|
@ -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")
|
||||||
|
@ -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}")
|
|
@ -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()
|
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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:
|
||||||
|
@ -1 +0,0 @@
|
|||||||
|
|
@ -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'
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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 ###
|
|
||||||
|
|
@ -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 ###
|
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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 ###
|
|
@ -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 ###
|
|
@ -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 ###
|
|
||||||
|
|
@ -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 ###
|
|
@ -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 ###
|
|
@ -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 ###
|
|
||||||
|
|
@ -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 ###
|
|
@ -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 ###
|
|
@ -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 ###
|
|
@ -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 ###
|
|
||||||
|
|
@ -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 ###
|
|
@ -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'))
|
||||||
|
|
@ -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 ###
|
@ -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)
|
||||||
|
@ -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 ###
|
@ -28,7 +28,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from .. import epdconfig
|
from . import epdconfig
|
||||||
|
|
||||||
# Display resolution
|
# Display resolution
|
||||||
EPD_WIDTH = 128
|
EPD_WIDTH = 128
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from .. import epdconfig
|
from . import epdconfig
|
||||||
|
|
||||||
# Display resolution
|
# Display resolution
|
||||||
EPD_WIDTH = 800
|
EPD_WIDTH = 800
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
|
@ -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()
|
||||||
|
@ -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()
|
|
||||||
|
@ -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()
|
|
@ -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()
|
||||||
|
@ -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()
|
|
||||||
|
@ -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()
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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
Reference in New Issue
Block a user