mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
Merge branch 'jayofelony:master' into master
This commit is contained in:
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@ -1,4 +1,3 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: jayofelony
|
github: jayofelony
|
||||||
custom: https://tikkie.me/pay/dubcto94hnskg539kar0
|
|
19
.idea/deployment.xml
generated
19
.idea/deployment.xml
generated
@ -1,23 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="PublishConfigData" serverName="pwnagotchi" filePermissions="493" folderPermissions="493" remoteFilesAllowedToDisappearOnAutoupload="false" confirmBeforeUploading="false">
|
<component name="PublishConfigData" filePermissions="493" folderPermissions="493" remoteFilesAllowedToDisappearOnAutoupload="false" confirmBeforeUploading="false">
|
||||||
<option name="confirmBeforeUploading" value="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>
|
</component>
|
||||||
</project>
|
</project>
|
17
Makefile
17
Makefile
@ -1,4 +1,4 @@
|
|||||||
PACKER_VERSION := 1.10.1
|
PACKER_VERSION := 1.11.0
|
||||||
PWN_HOSTNAME := pwnagotchi
|
PWN_HOSTNAME := pwnagotchi
|
||||||
PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py)
|
PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py)
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ UNSHARE := $(UNSHARE) --uts
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# sudo apt-get install qemu-user-static qemu-utils
|
# sudo apt-get install qemu-user-static qemu-utils
|
||||||
all: clean packer image
|
all: packer image
|
||||||
|
|
||||||
update_langs:
|
update_langs:
|
||||||
@for lang in pwnagotchi/locale/*/; do\
|
@for lang in pwnagotchi/locale/*/; do\
|
||||||
@ -40,22 +40,23 @@ compile_langs:
|
|||||||
./scripts/language.sh compile $$(basename $$lang); \
|
./scripts/language.sh compile $$(basename $$lang); \
|
||||||
done
|
done
|
||||||
|
|
||||||
packer: clean
|
packer:
|
||||||
curl https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_amd64.zip -o /tmp/packer.zip
|
curl https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_amd64.zip -o /tmp/packer.zip
|
||||||
unzip /tmp/packer.zip -d /tmp
|
unzip -o /tmp/packer.zip -d /tmp
|
||||||
sudo mv /tmp/packer /usr/bin/packer
|
sudo mv /tmp/packer /usr/bin/packer
|
||||||
|
|
||||||
image: clean packer
|
image: packer
|
||||||
export LC_ALL=en_GB.UTF-8
|
export LC_ALL=en_GB.UTF-8
|
||||||
cd builder && sudo /usr/bin/packer init combined.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" combined.json.pkr.hcl
|
cd builder && sudo /usr/bin/packer init combined.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" combined.json.pkr.hcl
|
||||||
|
|
||||||
bullseye: clean packer
|
32bit: packer
|
||||||
export LC_ALL=en_GB.UTF-8
|
export LC_ALL=en_GB.UTF-8
|
||||||
cd builder && sudo /usr/bin/packer init raspberrypi32.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" raspberrypi32.json.pkr.hcl
|
cd builder && sudo /usr/bin/packer init raspberrypi32.json.pkr.hcl && QEMU_CPU=arm1176 sudo -E $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" raspberrypi32.json.pkr.hcl
|
||||||
|
|
||||||
bookworm: clean packer
|
64bit: packer
|
||||||
export LC_ALL=en_GB.UTF-8
|
export LC_ALL=en_GB.UTF-8
|
||||||
cd builder && sudo /usr/bin/packer init raspberrypi64.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" raspberrypi64.json.pkr.hcl
|
cd builder && sudo /usr/bin/packer init raspberrypi64.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" raspberrypi64.json.pkr.hcl
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
- rm -rf /tmp/packer*
|
- rm -rf /tmp/packer*
|
||||||
|
- rm -rf /tmp/LICENSE.txt
|
||||||
|
@ -5,6 +5,8 @@ This is the main source for all forks:
|
|||||||
|
|
||||||
[GH Sponsor](https://github.com/sponsors/jayofelony)
|
[GH Sponsor](https://github.com/sponsors/jayofelony)
|
||||||
|
|
||||||
|
**Proudly partnering with [PiSugar](https://www.pisugar.com)!!**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Pwnagotchi](https://pwnagotchi.ai/) is an [A2C](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752)-based "AI" leveraging [bettercap](https://www.bettercap.org/) that learns from its surrounding Wi-Fi environment to maximize the crackable WPA key material it captures (either passively, or by performing authentication and association attacks). This material is collected as PCAP files containing any form of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
|
[Pwnagotchi](https://pwnagotchi.ai/) is an [A2C](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752)-based "AI" leveraging [bettercap](https://www.bettercap.org/) that learns from its surrounding Wi-Fi environment to maximize the crackable WPA key material it captures (either passively, or by performing authentication and association attacks). This material is collected as PCAP files containing any form of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
|
||||||
|
@ -60,7 +60,7 @@ def pwnagotchi_cli():
|
|||||||
channels = agent.get_access_points_by_channel()
|
channels = agent.get_access_points_by_channel()
|
||||||
# for each channel
|
# for each channel
|
||||||
for ch, aps in channels:
|
for ch, aps in channels:
|
||||||
time.sleep(0.2)
|
time.sleep(0.5)
|
||||||
agent.set_channel(ch)
|
agent.set_channel(ch)
|
||||||
|
|
||||||
if not agent.is_stale() and agent.any_activity():
|
if not agent.is_stale() and agent.any_activity():
|
||||||
@ -237,7 +237,7 @@ def pwnagotchi_cli():
|
|||||||
f.write("ui.display.enabled = true\n")
|
f.write("ui.display.enabled = true\n")
|
||||||
pwn_display_type = input("What display do you use?\n\n"
|
pwn_display_type = input("What display do you use?\n\n"
|
||||||
"Be sure to check for the correct display type @ \n"
|
"Be sure to check for the correct display type @ \n"
|
||||||
"https://github.com/jayofelony/pwnagotchi/blob/master/pwnagotchi/utils.py#L240-L431\n\n"
|
"https://github.com/jayofelony/pwnagotchi/blob/master/pwnagotchi/utils.py#L240-L501\n\n"
|
||||||
"Display type: ")
|
"Display type: ")
|
||||||
if pwn_display_type != "":
|
if pwn_display_type != "":
|
||||||
f.write(f"ui.display.type = \"{pwn_display_type}\"\n")
|
f.write(f"ui.display.type = \"{pwn_display_type}\"\n")
|
||||||
|
@ -25,7 +25,7 @@ source "arm" "rpi64-pwnagotchi" {
|
|||||||
file_checksum_type = "sha256"
|
file_checksum_type = "sha256"
|
||||||
file_target_extension = "xz"
|
file_target_extension = "xz"
|
||||||
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
||||||
image_path = "../pwnagotchi-64bit.img"
|
image_path = "../../../pwnagotchi-64bit.img"
|
||||||
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
||||||
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
||||||
image_build_method = "resize"
|
image_build_method = "resize"
|
||||||
@ -50,12 +50,12 @@ source "arm" "rpi64-pwnagotchi" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source "arm" "rpi32-pwnagotchi" {
|
source "arm" "rpi32-pwnagotchi" {
|
||||||
file_checksum_url = "https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2024-03-12/2024-03-12-raspios-bullseye-armhf-lite.img.xz.sha256"
|
file_checksum_url = "https://downloads.raspberrypi.com/raspios_lite_armhf/images/raspios_lite_armhf-2024-03-15/2024-03-15-raspios-bookworm-armhf-lite.img.xz.sha256"
|
||||||
file_urls = ["https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2024-03-12/2024-03-12-raspios-bullseye-armhf-lite.img.xz"]
|
file_urls = ["https://downloads.raspberrypi.com/raspios_lite_armhf/images/raspios_lite_armhf-2024-03-15/2024-03-15-raspios-bookworm-armhf-lite.img.xz"]
|
||||||
file_checksum_type = "sha256"
|
file_checksum_type = "sha256"
|
||||||
file_target_extension = "xz"
|
file_target_extension = "xz"
|
||||||
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
||||||
image_path = "../pwnagotchi-32bit.img"
|
image_path = "../../../pwnagotchi-32bit.img"
|
||||||
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
image_build_method = "resize"
|
image_build_method = "resize"
|
||||||
@ -67,7 +67,7 @@ source "arm" "rpi32-pwnagotchi" {
|
|||||||
start_sector = "8192"
|
start_sector = "8192"
|
||||||
filesystem = "fat"
|
filesystem = "fat"
|
||||||
size = "256M"
|
size = "256M"
|
||||||
mountpoint = "/boot"
|
mountpoint = "/boot/firmware"
|
||||||
}
|
}
|
||||||
image_partitions {
|
image_partitions {
|
||||||
name = "root"
|
name = "root"
|
||||||
@ -101,6 +101,13 @@ build {
|
|||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
inline = ["chmod +x /usr/bin/*"]
|
inline = ["chmod +x /usr/bin/*"]
|
||||||
}
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["mkdir -p /usr/local/src/pwnagotchi"]
|
||||||
|
}
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/usr/local/src/pwnagotchi/"
|
||||||
|
source = "../"
|
||||||
|
}
|
||||||
|
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/etc/systemd/system/"
|
destination = "/etc/systemd/system/"
|
||||||
@ -142,10 +149,16 @@ build {
|
|||||||
"data/32bit/usr/bin/pwnlib",
|
"data/32bit/usr/bin/pwnlib",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["mkdir -p /usr/local/src/pwnagotchi"]
|
||||||
|
}
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/usr/local/src/pwnagotchi/"
|
||||||
|
source = "../"
|
||||||
|
}
|
||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
inline = ["chmod +x /usr/bin/*"]
|
inline = ["chmod +x /usr/bin/*"]
|
||||||
}
|
}
|
||||||
|
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/etc/systemd/system/"
|
destination = "/etc/systemd/system/"
|
||||||
sources = [
|
sources = [
|
||||||
@ -167,7 +180,6 @@ build {
|
|||||||
provisioner "ansible-local" {
|
provisioner "ansible-local" {
|
||||||
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
||||||
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
||||||
playbook_dir = "extras/"
|
|
||||||
playbook_file = "raspberrypi32.yml"
|
playbook_file = "raspberrypi32.yml"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,67 +0,0 @@
|
|||||||
# For more options and information see
|
|
||||||
# http://rptl.io/configtxt
|
|
||||||
# Some settings may impact device functionality. See link above for details
|
|
||||||
|
|
||||||
# Uncomment some or all of these to enable the optional hardware interfaces
|
|
||||||
#dtparam=i2c_arm=on
|
|
||||||
#dtparam=i2s=on
|
|
||||||
#dtparam=spi=on
|
|
||||||
|
|
||||||
# Enable audio (loads snd_bcm2835)
|
|
||||||
dtparam=audio=on
|
|
||||||
|
|
||||||
# Additional overlays and parameters are documented
|
|
||||||
# /boot/overlays/README
|
|
||||||
|
|
||||||
# Automatically load overlays for detected cameras
|
|
||||||
camera_auto_detect=1
|
|
||||||
|
|
||||||
# Automatically load overlays for detected DSI displays
|
|
||||||
display_auto_detect=1
|
|
||||||
|
|
||||||
# Automatically load initramfs files, if found
|
|
||||||
auto_initramfs=1
|
|
||||||
|
|
||||||
# Enable DRM VC4 V3D driver
|
|
||||||
dtoverlay=vc4-kms-v3d
|
|
||||||
max_framebuffers=2
|
|
||||||
|
|
||||||
# Don't have the firmware create an initial video= setting in cmdline.txt.
|
|
||||||
# Use the kernel's default instead.
|
|
||||||
disable_fw_kms_setup=1
|
|
||||||
|
|
||||||
# Run in 64-bit mode
|
|
||||||
arm_64bit=0
|
|
||||||
|
|
||||||
# Disable compensation for displays with overscan
|
|
||||||
disable_overscan=1
|
|
||||||
|
|
||||||
# Run as fast as firmware / board allows
|
|
||||||
arm_boost=1
|
|
||||||
|
|
||||||
[cm4]
|
|
||||||
# Enable host mode on the 2711 built-in XHCI USB controller.
|
|
||||||
# This line should be removed if the legacy DWC2 controller is required
|
|
||||||
# (e.g. for USB device mode) or if USB support is not required.
|
|
||||||
otg_mode=1
|
|
||||||
|
|
||||||
[all]
|
|
||||||
dtoverlay=dwc2
|
|
||||||
dtparam=i2c1=on
|
|
||||||
dtparam=i2c_arm=on
|
|
||||||
dtparam=spi=on
|
|
||||||
gpu_mem=1
|
|
||||||
dtoverlay=dwc2
|
|
||||||
#dtoverlay=disable-wifi
|
|
||||||
|
|
||||||
[pi0]
|
|
||||||
dtoverlay=spi1-3cs
|
|
||||||
#dtoverlay=disable-wifi
|
|
||||||
|
|
||||||
[pi3]
|
|
||||||
dtoverlay=spi1-3cs
|
|
||||||
#dtoverlay=disable-wifi
|
|
||||||
|
|
||||||
[pi4]
|
|
||||||
dtoverlay=spi1-3cs
|
|
||||||
#dtoverlay=disable-wifi
|
|
@ -0,0 +1,5 @@
|
|||||||
|
[main]
|
||||||
|
plugins=keyfile,ifupdown
|
||||||
|
|
||||||
|
[ifupdown]
|
||||||
|
managed=true
|
@ -1,62 +0,0 @@
|
|||||||
# A sample configuration for dhcpcd.
|
|
||||||
# See dhcpcd.conf(5) for details.
|
|
||||||
|
|
||||||
# Allow users of this group to interact with dhcpcd via the control socket.
|
|
||||||
#controlgroup wheel
|
|
||||||
|
|
||||||
# Inform the DHCP server of our hostname for DDNS.
|
|
||||||
hostname
|
|
||||||
|
|
||||||
# Use the hardware address of the interface for the Client ID.
|
|
||||||
clientid
|
|
||||||
# or
|
|
||||||
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
|
|
||||||
# Some non-RFC compliant DHCP servers do not reply with this set.
|
|
||||||
# In this case, comment out duid and enable clientid above.
|
|
||||||
#duid
|
|
||||||
|
|
||||||
# Persist interface configuration when dhcpcd exits.
|
|
||||||
persistent
|
|
||||||
|
|
||||||
# Rapid commit support.
|
|
||||||
# Safe to enable by default because it requires the equivalent option set
|
|
||||||
# on the server to actually work.
|
|
||||||
option rapid_commit
|
|
||||||
|
|
||||||
# A list of options to request from the DHCP server.
|
|
||||||
option domain_name_servers, domain_name, domain_search, host_name
|
|
||||||
option classless_static_routes
|
|
||||||
# Respect the network MTU. This is applied to DHCP routes.
|
|
||||||
option interface_mtu
|
|
||||||
|
|
||||||
# Most distributions have NTP support.
|
|
||||||
#option ntp_servers
|
|
||||||
|
|
||||||
# A ServerID is required by RFC2131.
|
|
||||||
require dhcp_server_identifier
|
|
||||||
|
|
||||||
# Generate SLAAC address using the Hardware Address of the interface
|
|
||||||
#slaac hwaddr
|
|
||||||
# OR generate Stable Private IPv6 Addresses based from the DUID
|
|
||||||
slaac private
|
|
||||||
|
|
||||||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
# !! DO NOT EDIT THESE LINES BELOW PLEASE !!
|
|
||||||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
|
|
||||||
# static IP configuration:
|
|
||||||
denyinterfaces wlan0
|
|
||||||
|
|
||||||
interface eth0
|
|
||||||
static domain_name_servers=8.8.8.8 1.1.1.1
|
|
||||||
metric 201
|
|
||||||
|
|
||||||
interface usb0
|
|
||||||
static ip_address=10.0.0.2/24
|
|
||||||
static routers=10.0.0.1
|
|
||||||
static domain_name_servers=10.0.0.1 8.8.8.8 1.1.1.1
|
|
||||||
metric 202
|
|
||||||
|
|
||||||
interface bnep0
|
|
||||||
static domain_name_servers=8.8.8.8 1.1.1.1
|
|
||||||
metric 203
|
|
2
builder/data/32bit/etc/network/interfaces.d/eth0-cfg
Normal file
2
builder/data/32bit/etc/network/interfaces.d/eth0-cfg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
allow-hotplug eth0
|
||||||
|
iface eth0 inet dhcp
|
2
builder/data/32bit/etc/network/interfaces.d/lo-cfg
Normal file
2
builder/data/32bit/etc/network/interfaces.d/lo-cfg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
auto lo
|
||||||
|
iface lo inet loopback
|
8
builder/data/32bit/etc/network/interfaces.d/usb0-cfg
Normal file
8
builder/data/32bit/etc/network/interfaces.d/usb0-cfg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
allow-hotplug usb0
|
||||||
|
iface usb0 inet static
|
||||||
|
address 10.0.0.2
|
||||||
|
netmask 255.255.255.0
|
||||||
|
network 10.0.0.0
|
||||||
|
broadcast 10.0.0.255
|
||||||
|
gateway 10.0.0.1
|
||||||
|
metric 101
|
2
builder/data/32bit/etc/network/interfaces.d/wlan0-cfg
Normal file
2
builder/data/32bit/etc/network/interfaces.d/wlan0-cfg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
allow-hotplug wlan0
|
||||||
|
iface wlan0 inet static
|
@ -1,70 +0,0 @@
|
|||||||
# For more options and information see
|
|
||||||
# http://rptl.io/configtxt
|
|
||||||
# Some settings may impact device functionality. See link above for details
|
|
||||||
|
|
||||||
# Uncomment some or all of these to enable the optional hardware interfaces
|
|
||||||
#dtparam=i2c_arm=on
|
|
||||||
#dtparam=i2s=on
|
|
||||||
#dtparam=spi=on
|
|
||||||
|
|
||||||
# Enable audio (loads snd_bcm2835)
|
|
||||||
dtparam=audio=on
|
|
||||||
|
|
||||||
# Additional overlays and parameters are documented
|
|
||||||
# /boot/firmware/overlays/README
|
|
||||||
|
|
||||||
# Automatically load overlays for detected cameras
|
|
||||||
camera_auto_detect=1
|
|
||||||
|
|
||||||
# Automatically load overlays for detected DSI displays
|
|
||||||
display_auto_detect=1
|
|
||||||
|
|
||||||
# Automatically load initramfs files, if found
|
|
||||||
auto_initramfs=1
|
|
||||||
|
|
||||||
# Enable DRM VC4 V3D driver
|
|
||||||
dtoverlay=vc4-kms-v3d
|
|
||||||
max_framebuffers=2
|
|
||||||
|
|
||||||
# Don't have the firmware create an initial video= setting in cmdline.txt.
|
|
||||||
# Use the kernel's default instead.
|
|
||||||
disable_fw_kms_setup=1
|
|
||||||
|
|
||||||
# Run in 64-bit mode
|
|
||||||
arm_64bit=1
|
|
||||||
|
|
||||||
# Disable compensation for displays with overscan
|
|
||||||
disable_overscan=1
|
|
||||||
|
|
||||||
# Run as fast as firmware / board allows
|
|
||||||
arm_boost=1
|
|
||||||
|
|
||||||
[cm4]
|
|
||||||
# Enable host mode on the 2711 built-in XHCI USB controller.
|
|
||||||
# This line should be removed if the legacy DWC2 controller is required
|
|
||||||
# (e.g. for USB device mode) or if USB support is not required.
|
|
||||||
otg_mode=1
|
|
||||||
|
|
||||||
[all]
|
|
||||||
dtparam=i2c1=on
|
|
||||||
dtparam=i2c_arm=on
|
|
||||||
dtparam=spi=on
|
|
||||||
gpu_mem=1
|
|
||||||
dtoverlay=dwc2
|
|
||||||
#dtoverlay=disable-wifi
|
|
||||||
|
|
||||||
[pi0]
|
|
||||||
dtoverlay=spi0-0cs
|
|
||||||
#dtoverlay=disable-wifi
|
|
||||||
|
|
||||||
[pi3]
|
|
||||||
dtoverlay=spi0-0cs
|
|
||||||
#dtoverlay=disable-wifi
|
|
||||||
|
|
||||||
[pi4]
|
|
||||||
dtoverlay=spi0-0cs
|
|
||||||
#dtoverlay=disable-wifi
|
|
||||||
|
|
||||||
[pi5]
|
|
||||||
dtoverlay=spi0-0cs
|
|
||||||
#dtoverlay=disable-wifi
|
|
@ -8,7 +8,6 @@ After=pwngrid-peer.service
|
|||||||
Type=simple
|
Type=simple
|
||||||
WorkingDirectory=~
|
WorkingDirectory=~
|
||||||
ExecStart=/usr/bin/pwnagotchi-launcher
|
ExecStart=/usr/bin/pwnagotchi-launcher
|
||||||
ExecStopPost=/usr/bin/bash -c "if egrep -qi 'personality.clear_on_exit[ =]*true' /etc/pwnagotchi/config.toml ; then /usr/local/bin/pwnagotchi --clear; fi"
|
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=30
|
RestartSec=30
|
||||||
TasksMax=infinity
|
TasksMax=infinity
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
# Install nexmon to fix wireless scanning (takes 2.5G of space)
|
|
||||||
- name: clone nexmon repository
|
|
||||||
git:
|
|
||||||
repo: https://github.com/DrSchottky/nexmon.git
|
|
||||||
dest: /usr/local/src/nexmon
|
|
||||||
|
|
||||||
- name: make firmware
|
|
||||||
shell: "source ./setup_env.sh && make"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
chdir: /usr/local/src/nexmon/
|
|
||||||
|
|
||||||
- name: "make firmware patch ({{ item.name }})"
|
|
||||||
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/{{ item.patch }}/nexmon/ && make"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
chdir: /usr/local/src/nexmon/
|
|
||||||
environment:
|
|
||||||
QEMU_UNAME: "{{ item.kernel }}"
|
|
||||||
ARCHFLAGS: "{{ item.arch_flags }}"
|
|
||||||
|
|
||||||
- name: "install new firmware ({{ item.name }})"
|
|
||||||
copy:
|
|
||||||
src: "/usr/local/src/nexmon/patches/{{ item.patch }}/nexmon/{{ item.firmware }}"
|
|
||||||
dest: "/usr/lib/firmware/brcm/{{ item.firmware }}"
|
|
||||||
follow: true
|
|
||||||
environment:
|
|
||||||
QEMU_UNAME: "{{ item.kernel }}"
|
|
||||||
ARCHFLAGS: "{{ item.arch_flags }}"
|
|
||||||
|
|
||||||
- name: backup original driver
|
|
||||||
command: "mv /usr/lib/modules/{{ item.kernel }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz /usr/lib/modules/{{ item.kernel }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig"
|
|
||||||
|
|
||||||
- name: copy modified driver
|
|
||||||
copy:
|
|
||||||
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_6.1.y-nexmon/brcmfmac.ko"
|
|
||||||
dest: "/usr/lib/modules/{{ item.kernel }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
|
|
||||||
|
|
||||||
- name : load brcmfmac drivers
|
|
||||||
command: "/sbin/depmod -a {{ item.kernel }}"
|
|
@ -1,8 +1,8 @@
|
|||||||
packer {
|
packer {
|
||||||
required_plugins {
|
required_plugins {
|
||||||
arm = {
|
arm = {
|
||||||
version = "1.0.0"
|
version = ">=1.0.0"
|
||||||
source = "github.com/cdecoux/builder-arm"
|
source = "github.com/michalfita/cross"
|
||||||
}
|
}
|
||||||
ansible = {
|
ansible = {
|
||||||
source = "github.com/hashicorp/ansible"
|
source = "github.com/hashicorp/ansible"
|
||||||
@ -20,12 +20,12 @@ variable "pwn_version" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source "arm" "rpi32-pwnagotchi" {
|
source "arm" "rpi32-pwnagotchi" {
|
||||||
file_checksum_url = "https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2024-03-12/2024-03-12-raspios-bullseye-armhf-lite.img.xz.sha256"
|
file_checksum_url = "https://downloads.raspberrypi.com/raspios_lite_armhf/images/raspios_lite_armhf-2024-03-15/2024-03-15-raspios-bookworm-armhf-lite.img.xz.sha256"
|
||||||
file_urls = ["https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2024-03-12/2024-03-12-raspios-bullseye-armhf-lite.img.xz"]
|
file_urls = ["https://downloads.raspberrypi.com/raspios_lite_armhf/images/raspios_lite_armhf-2024-03-15/2024-03-15-raspios-bookworm-armhf-lite.img.xz"]
|
||||||
file_checksum_type = "sha256"
|
file_checksum_type = "sha256"
|
||||||
file_target_extension = "xz"
|
file_target_extension = "xz"
|
||||||
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
||||||
image_path = "../../pwnagotchi-32bit.img"
|
image_path = "../../../pwnagotchi-32bit.img"
|
||||||
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
image_build_method = "resize"
|
image_build_method = "resize"
|
||||||
@ -37,7 +37,7 @@ source "arm" "rpi32-pwnagotchi" {
|
|||||||
start_sector = "8192"
|
start_sector = "8192"
|
||||||
filesystem = "fat"
|
filesystem = "fat"
|
||||||
size = "256M"
|
size = "256M"
|
||||||
mountpoint = "/boot"
|
mountpoint = "/boot/firmware"
|
||||||
}
|
}
|
||||||
image_partitions {
|
image_partitions {
|
||||||
name = "root"
|
name = "root"
|
||||||
@ -51,6 +51,9 @@ source "arm" "rpi32-pwnagotchi" {
|
|||||||
build {
|
build {
|
||||||
name = "Raspberry Pi 32 Pwnagotchi"
|
name = "Raspberry Pi 32 Pwnagotchi"
|
||||||
sources = ["source.arm.rpi32-pwnagotchi"]
|
sources = ["source.arm.rpi32-pwnagotchi"]
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["uname -m"]
|
||||||
|
}
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/usr/bin/"
|
destination = "/usr/bin/"
|
||||||
sources = [
|
sources = [
|
||||||
@ -66,7 +69,13 @@ build {
|
|||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
inline = ["chmod +x /usr/bin/*"]
|
inline = ["chmod +x /usr/bin/*"]
|
||||||
}
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["mkdir -p /usr/local/src/pwnagotchi"]
|
||||||
|
}
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/usr/local/src/pwnagotchi/"
|
||||||
|
source = "../"
|
||||||
|
}
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/etc/systemd/system/"
|
destination = "/etc/systemd/system/"
|
||||||
sources = [
|
sources = [
|
||||||
@ -88,7 +97,6 @@ build {
|
|||||||
provisioner "ansible-local" {
|
provisioner "ansible-local" {
|
||||||
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
||||||
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
||||||
playbook_dir = "extras/"
|
|
||||||
playbook_file = "raspberrypi32.yml"
|
playbook_file = "raspberrypi32.yml"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,46 +4,15 @@
|
|||||||
gather_facts: true
|
gather_facts: true
|
||||||
become: true
|
become: true
|
||||||
vars:
|
vars:
|
||||||
boards:
|
|
||||||
- {
|
|
||||||
kernel: "6.1.21+",
|
|
||||||
name: "PiZeroW",
|
|
||||||
firmware: "brcmfmac43430-sdio.bin",
|
|
||||||
patch: "bcm43430a1/7_45_41_46",
|
|
||||||
cpu: arm1176,
|
|
||||||
arch_flags: "-arch armv6l"
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
kernel: "6.1.21-v7+",
|
|
||||||
name: "PiZero2W",
|
|
||||||
firmware: "brcmfmac43436-sdio.bin",
|
|
||||||
patch: "bcm43436b0/9_88_4_65",
|
|
||||||
cpu: any, #cortex-a53
|
|
||||||
arch_flags: "-arch armv7l"
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
kernel: "6.1.21-v7l+",
|
|
||||||
name: "Pi4b_32",
|
|
||||||
firmware: "brcmfmac43455-sdio.bin",
|
|
||||||
patch: "bcm43455c0/7_45_206",
|
|
||||||
cpu: any, #cortex-a72
|
|
||||||
arch_flags: "-arch armv7l"
|
|
||||||
}
|
|
||||||
kernel:
|
kernel:
|
||||||
min: "6.1"
|
min: "6.6"
|
||||||
full: "6.1.21+"
|
full: "6.6.31+rpt-rpi-v6"
|
||||||
full_2w: "6.1.21-v7+"
|
|
||||||
full_4b: "6.1.21-v7l+"
|
|
||||||
arch: "v6l"
|
|
||||||
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', true) }}"
|
||||||
custom_plugin_dir: "/usr/local/share/pwnagotchi/custom-plugins"
|
|
||||||
services:
|
services:
|
||||||
enable:
|
enable:
|
||||||
- bettercap.service
|
- bettercap.service
|
||||||
- bluetooth.service
|
|
||||||
- dphys-swapfile.service
|
|
||||||
- fstrim.timer
|
- fstrim.timer
|
||||||
- pwnagotchi.service
|
- pwnagotchi.service
|
||||||
- pwngrid-peer.service
|
- pwngrid-peer.service
|
||||||
@ -52,25 +21,24 @@
|
|||||||
- apt-daily-upgrade.timer
|
- apt-daily-upgrade.timer
|
||||||
- apt-daily.service
|
- apt-daily.service
|
||||||
- apt-daily.timer
|
- apt-daily.timer
|
||||||
|
- 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"
|
||||||
|
branch: "lite" # or master
|
||||||
bettercap:
|
bettercap:
|
||||||
source: "https://github.com/jayofelony/bettercap.git"
|
source: "https://github.com/jayofelony/bettercap.git"
|
||||||
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.2/bettercap-2.32.2-armhf.zip"
|
branch: "lite" # or master
|
||||||
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
|
pwngrid:
|
||||||
opwngrid:
|
|
||||||
source: "https://github.com/jayofelony/pwngrid.git"
|
source: "https://github.com/jayofelony/pwngrid.git"
|
||||||
url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.7/pwngrid-1.10.7-armhf.zip"
|
url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.7/pwngrid-1.10.7-armhf.zip"
|
||||||
torch:
|
torch:
|
||||||
wheel: "torch-2.1.0a0+gitunknown-cp39-cp39-linux_armv6l.whl"
|
wheel: "torch-2.1.0a0+gita8e7c98-cp311-cp311-linux_armv6l.whl"
|
||||||
url: "https://github.com/Sniffleupagus/Torch4Pizero/releases/download/v1.0.0/torch-2.1.0a0+gitunknown-cp39-cp39-linux_armv6l.whl"
|
url: "https://github.com/Sniffleupagus/Torch4Pizero/releases/download/py0torch-bookworm-2024-05/torch-2.1.0a0+gita8e7c98-cp311-cp311-linux_armv6l.whl"
|
||||||
torchvision:
|
torchvision:
|
||||||
wheel: "torchvision-0.16.0a0-cp39-cp39-linux_armv6l.whl"
|
wheel: "torchvision-0.16.0+fbb4cc5-cp311-cp311-linux_armv6l.whl"
|
||||||
url: "https://github.com/Sniffleupagus/Torch4Pizero/releases/download/v1.0.0/torchvision-0.16.0a0-cp39-cp39-linux_armv6l.whl"
|
url: "https://github.com/Sniffleupagus/Torch4Pizero/releases/download/py0torch-bookworm-2024-05/torchvision-0.16.0+fbb4cc5-cp311-cp311-linux_armv6l.whl"
|
||||||
apt:
|
apt:
|
||||||
downgrade:
|
downgrade:
|
||||||
- libpcap-dev_1.9.1-4_armhf.deb
|
- libpcap-dev_1.9.1-4_armhf.deb
|
||||||
@ -85,109 +53,145 @@
|
|||||||
- firmware-realtek
|
- 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
|
|
||||||
- nfs-common
|
- nfs-common
|
||||||
- triggerhappy
|
- triggerhappy
|
||||||
- wpasupplicant
|
- wpasupplicant
|
||||||
install:
|
install:
|
||||||
|
- aircrack-ng
|
||||||
- autoconf
|
- autoconf
|
||||||
- bc
|
|
||||||
- bison
|
- bison
|
||||||
- bluez
|
- bluez
|
||||||
- bluez-tools
|
- bluez-tools
|
||||||
- build-essential
|
- build-essential
|
||||||
- curl
|
- curl
|
||||||
- dkms
|
|
||||||
- dphys-swapfile
|
- dphys-swapfile
|
||||||
- espeak-ng
|
|
||||||
- evtest
|
|
||||||
- fbi
|
- fbi
|
||||||
|
- firmware-atheros
|
||||||
|
- firmware-brcm80211
|
||||||
|
- firmware-libertas
|
||||||
|
- firmware-misc-nonfree
|
||||||
|
- firmware-realtek
|
||||||
- flex
|
- flex
|
||||||
- fonts-dejavu
|
|
||||||
- fonts-dejavu-core
|
|
||||||
- fonts-dejavu-extra
|
|
||||||
- fonts-freefont-ttf
|
|
||||||
- g++
|
- g++
|
||||||
- gawk
|
- gawk
|
||||||
- gcc-arm-none-eabi
|
- gcc-arm-none-eabi
|
||||||
- git
|
- git
|
||||||
- libatlas-base-dev
|
- libatlas-base-dev
|
||||||
- libavcodec58
|
|
||||||
- libavformat58
|
|
||||||
- libblas-dev
|
|
||||||
- libbluetooth-dev
|
|
||||||
- libbz2-dev
|
|
||||||
- libc-ares-dev
|
|
||||||
- libc6-dev
|
- libc6-dev
|
||||||
- libcpuinfo-dev
|
- libcpuinfo-dev
|
||||||
|
- libcurl-ocaml-dev
|
||||||
- libdbus-1-dev
|
- libdbus-1-dev
|
||||||
- libdbus-glib-1-dev
|
- libdbus-glib-1-dev
|
||||||
- libeigen3-dev
|
|
||||||
- libelf-dev
|
|
||||||
- libffi-dev
|
|
||||||
- libfl-dev
|
- libfl-dev
|
||||||
- libfuse-dev
|
|
||||||
- libgdbm-dev
|
|
||||||
- libgl1-mesa-glx
|
|
||||||
- libgmp3-dev
|
- libgmp3-dev
|
||||||
- libgstreamer1.0-0
|
|
||||||
- libhdf5-dev
|
|
||||||
- liblapack-dev
|
|
||||||
- libncursesw5-dev
|
|
||||||
- libnetfilter-queue-dev
|
- libnetfilter-queue-dev
|
||||||
- libopenblas-dev
|
- libopenblas-dev # https://stackoverflow.com/questions/14570011/explain-why-numpy-should-not-be-imported-from-source-directory
|
||||||
- libopenjp2-7
|
- libopenjp2-7
|
||||||
- libopenmpi-dev
|
|
||||||
- libopenmpi3
|
|
||||||
- libpcap-dev
|
- libpcap-dev
|
||||||
- libprotobuf-dev
|
|
||||||
- libraspberrypi-bin
|
- libraspberrypi-bin
|
||||||
- libraspberrypi-dev
|
- libraspberrypi-dev
|
||||||
- libraspberrypi-doc
|
- libraspberrypi-doc
|
||||||
- libraspberrypi0
|
- libraspberrypi0
|
||||||
- libsleef-dev
|
- libsleef-dev
|
||||||
- libsqlite3-dev
|
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
- libswscale5
|
- libssl-ocaml-dev
|
||||||
- libtiff5
|
|
||||||
- libtool
|
- libtool
|
||||||
- libts-bin
|
|
||||||
- libusb-1.0-0-dev
|
- libusb-1.0-0-dev
|
||||||
- lsof
|
|
||||||
- make
|
- make
|
||||||
- ntp
|
- ntp
|
||||||
- python3-dbus
|
- pkg-config
|
||||||
- python3-flask
|
- python3-dev
|
||||||
- python3-flask-cors
|
|
||||||
- python3-flaskext.wtf
|
|
||||||
- python3-pil
|
|
||||||
- python3-pip
|
- python3-pip
|
||||||
- python3-protobuf
|
- python3-protobuf
|
||||||
- python3-smbus
|
- python3-setuptools
|
||||||
- qpdf
|
- qpdf
|
||||||
- raspberrypi-kernel-headers
|
- raspberrypi-kernel-headers
|
||||||
- rsync
|
- rsync
|
||||||
- screen
|
|
||||||
- tcpdump
|
- tcpdump
|
||||||
- texinfo
|
- texinfo
|
||||||
- time
|
|
||||||
- tk-dev
|
|
||||||
- unzip
|
- unzip
|
||||||
- vim
|
|
||||||
- wget
|
- wget
|
||||||
- wl
|
- wl
|
||||||
- xxd
|
- xxd
|
||||||
- zlib1g-dev
|
- zlib1g-dev
|
||||||
|
environment:
|
||||||
|
ARCHFLAGS: "-arch armv6l"
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
# First we install packages
|
||||||
|
- name: install packages
|
||||||
|
apt:
|
||||||
|
name: "{{ packages.apt.install }}"
|
||||||
|
state: latest
|
||||||
|
update_cache: yes
|
||||||
|
install_recommends: no
|
||||||
|
|
||||||
|
- name: update pip3, setuptools, wheel
|
||||||
|
shell: "python3 -m pip install --upgrade pip setuptools wheel --break-system-packages"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src
|
||||||
|
|
||||||
|
- name: install 32bit torch
|
||||||
|
shell: "python3 -m pip install {{ packages.torch.url }} {{ packages.torchvision.url }} --break-system-packages"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch armv6l"
|
||||||
|
|
||||||
|
# Now we set up /boot/firmware
|
||||||
- name: Create pi user
|
- name: Create pi user
|
||||||
copy:
|
copy:
|
||||||
dest: /boot/userconf
|
dest: /boot/firmware/userconf
|
||||||
content: |
|
content: |
|
||||||
pi:$6$3jNr0GA9KIyt4hmM$efeVIopdMQ8DGgEPCWWlbx3mJJNAYci1lEXGdlky0xPyjqwKNbwTL5SrCcpb4144C4IvzWjn7Iv.QjqmU7iyT/
|
pi:$5$733Efsksay$SEFUKemv8FaNAu6X4GUfxdSzSDh6PbpOcdtNe5b7Nt0
|
||||||
|
|
||||||
|
- name: enable ssh on boot
|
||||||
|
file:
|
||||||
|
path: /boot/firmware/ssh
|
||||||
|
state: touch
|
||||||
|
|
||||||
|
- name: remove current rc.local
|
||||||
|
file:
|
||||||
|
path: /etc/rc.local
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- 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: setup /boot/firmware/config.txt
|
||||||
|
blockinfile:
|
||||||
|
path: /boot/firmware/config.txt
|
||||||
|
insertafter: EOF
|
||||||
|
block: |
|
||||||
|
dtparam=i2c1=on
|
||||||
|
dtparam=i2c_arm=on
|
||||||
|
dtparam=spi=on
|
||||||
|
gpu_mem=1
|
||||||
|
dtoverlay=dwc2
|
||||||
|
#dtoverlay=disable-wifi
|
||||||
|
enable_uart=1
|
||||||
|
|
||||||
|
[pi0]
|
||||||
|
dtoverlay=spi0-0cs
|
||||||
|
#dtoverlay=disable-wifi
|
||||||
|
|
||||||
- name: change hostname
|
- name: change hostname
|
||||||
lineinfile:
|
lineinfile:
|
||||||
@ -206,31 +210,14 @@
|
|||||||
state: present
|
state: present
|
||||||
when: hostname.changed
|
when: hostname.changed
|
||||||
|
|
||||||
- name: Create custom plugin directory
|
# Now we disable sap and a2dp, we don't use them on rpi
|
||||||
file:
|
- name: disable sap plugin for bluetooth.service
|
||||||
path: '{{ pwnagotchi.custom_plugin_dir }}'
|
lineinfile:
|
||||||
state: directory
|
dest: /lib/systemd/system/bluetooth.service
|
||||||
|
regexp: '^ExecStart=/usr/libexec/bluetooth/bluetoothd$'
|
||||||
- name: remove current rc.local
|
line: 'ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp'
|
||||||
file:
|
|
||||||
path: /etc/rc.local
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: update apt package cache
|
|
||||||
apt:
|
|
||||||
update_cache: yes
|
|
||||||
|
|
||||||
- name: install packages
|
|
||||||
apt:
|
|
||||||
name: "{{ packages.apt.install }}"
|
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: update pip3, setuptools, wheel
|
|
||||||
shell: "python3 -m pip install --upgrade pip setuptools wheel"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
chdir: /usr/local/src
|
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
#
|
#
|
||||||
# libpcap v1.9 - build from source
|
# libpcap v1.9 - build from source
|
||||||
@ -264,17 +251,61 @@
|
|||||||
dest: /usr/local/lib/libpcap.so.0.8
|
dest: /usr/local/lib/libpcap.so.0.8
|
||||||
state: link
|
state: link
|
||||||
|
|
||||||
###############################################################
|
# install latest hcxtools
|
||||||
# Install nexmon to fix wireless scanning (takes 2.5G of space)
|
- name: clone hcxtools
|
||||||
###############################################################
|
git:
|
||||||
|
repo: https://github.com/ZerBea/hcxtools.git
|
||||||
|
dest: /usr/local/src/hcxtools
|
||||||
|
|
||||||
# Install nexmon for all boards
|
- name: install hcxtools
|
||||||
- name: build and install nexmon as needed
|
shell: "make && make install"
|
||||||
include_tasks: nexmon.yml
|
args:
|
||||||
loop: "{{ boards }}"
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/hcxtools
|
||||||
|
|
||||||
|
- name: remove hcxtools directory
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/hcxtools
|
||||||
|
|
||||||
|
# Installing nexmon
|
||||||
|
- name: clone nexmon repository
|
||||||
|
git:
|
||||||
|
repo: https://github.com/DrSchottky/nexmon.git
|
||||||
|
dest: /usr/local/src/nexmon
|
||||||
|
|
||||||
|
- name: make firmware
|
||||||
|
shell: "source ./setup_env.sh && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch armv6l"
|
||||||
|
|
||||||
|
- name: make firmware patch (bcm43430a1)
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/ && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch armv6l"
|
||||||
|
|
||||||
|
- name: install new firmware (bcm43430a1)
|
||||||
|
copy:
|
||||||
|
src: /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/brcmfmac43430-sdio.bin
|
||||||
|
dest: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
||||||
|
follow: true
|
||||||
|
|
||||||
|
- name: copy modified driver
|
||||||
|
copy:
|
||||||
|
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
|
||||||
|
dest: "/usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch armv6l"
|
||||||
|
|
||||||
# some pizero2w have the pizeroW wifi chip
|
|
||||||
# could this be a link instead of a copy? and force, only if not a link?
|
|
||||||
- name: copy 43430-sdio as 43436s-sdio for the special 43430/1 /2
|
- name: copy 43430-sdio as 43436s-sdio for the special 43430/1 /2
|
||||||
copy:
|
copy:
|
||||||
src: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
src: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
||||||
@ -289,9 +320,14 @@
|
|||||||
loop:
|
loop:
|
||||||
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.clm_blob
|
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.clm_blob
|
||||||
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.raspberrypi,model-zero-w.clm_blob
|
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.raspberrypi,model-zero-w.clm_blob
|
||||||
- /usr/lib/firmware/brcm/brcmfmac43430b0-sdio.raspberrypi,model-zero-2-w.clm_blob
|
|
||||||
- /usr/lib/firmware/brcm/brcmfmac43436-sdio.raspberrypi,model-zero-2-w.clm_blob
|
- name: backup original driver
|
||||||
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.raspberrypi,3-model-b.clm_blob
|
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: load brcmfmac drivers
|
||||||
|
command: "/sbin/depmod {{ kernel.full }}"
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
|
||||||
# To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation
|
# 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
|
||||||
@ -299,58 +335,36 @@
|
|||||||
state: absent
|
state: absent
|
||||||
path: /usr/local/src/nexmon/
|
path: /usr/local/src/nexmon/
|
||||||
|
|
||||||
- name: clone pwnagotchi repository
|
- name: Create custom config directory
|
||||||
git:
|
file:
|
||||||
repo: https://github.com/jayofelony/pwnagotchi.git
|
path: /etc/pwnagotchi/conf.d/
|
||||||
dest: /usr/local/src/pwnagotchi
|
state: directory
|
||||||
register: pwnagotchigit
|
|
||||||
|
#- name: clone pwnagotchi repository
|
||||||
|
# git:
|
||||||
|
# repo: https://github.com/jayofelony/pwnagotchi.git
|
||||||
|
# dest: /usr/local/src/pwnagotchi
|
||||||
|
|
||||||
# is this even necessary? Can't we just link from /home/pi/pwnagotchi to /usr/local/{bin,lib,etc}
|
|
||||||
# then just git update in the home dir and encourage hacking?
|
|
||||||
# make owned by pi.pi, and custom plugins.
|
|
||||||
- name: build pwnagotchi wheel
|
- name: build pwnagotchi wheel
|
||||||
command: "python3 setup.py sdist bdist_wheel"
|
command: "pip3 install . --no-cache-dir --break-system-packages"
|
||||||
args:
|
args:
|
||||||
chdir: /usr/local/src/pwnagotchi
|
chdir: /usr/local/src/pwnagotchi
|
||||||
when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version)
|
|
||||||
|
|
||||||
- name: download torch whl
|
|
||||||
get_url:
|
|
||||||
url: "{{ packages.torch.url }}"
|
|
||||||
dest: /usr/local/src/
|
|
||||||
|
|
||||||
- name: download torchvision whl
|
|
||||||
get_url:
|
|
||||||
url: "{{ packages.torchvision.url }}"
|
|
||||||
dest: /usr/local/src/
|
|
||||||
|
|
||||||
- name: install 32-bit pwnagotchi wheel and dependencies with 32-bit torch wheels
|
|
||||||
pip:
|
|
||||||
name:
|
|
||||||
- "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}"
|
|
||||||
- "{{ packages.torch.url }}"
|
|
||||||
- "{{ packages.torchvision.url }}"
|
|
||||||
extra_args: "--no-cache-dir"
|
|
||||||
environment:
|
|
||||||
QEMU_CPU: arm1176
|
|
||||||
QEMU_UNAME: "{{ kernel.full }}"
|
|
||||||
when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version)
|
|
||||||
|
|
||||||
- name: create /usr/local/share/pwnagotchi/ folder
|
- name: create /usr/local/share/pwnagotchi/ folder
|
||||||
file:
|
file:
|
||||||
path: /usr/local/share/pwnagotchi/
|
path: /usr/local/share/pwnagotchi/
|
||||||
state: directory
|
state: directory
|
||||||
|
|
||||||
|
- name: Create custom plugin directory
|
||||||
|
file:
|
||||||
|
path: /usr/local/share/pwnagotchi/custom-plugins/
|
||||||
|
state: directory
|
||||||
|
|
||||||
- name: remove pwnagotchi folder
|
- name: remove pwnagotchi folder
|
||||||
file:
|
file:
|
||||||
state: absent
|
state: absent
|
||||||
path: /usr/local/src/pwnagotchi
|
path: /usr/local/src/pwnagotchi
|
||||||
|
|
||||||
- name: remove torch whl
|
|
||||||
file:
|
|
||||||
state: absent
|
|
||||||
path: "{{ lookup('fileglob', '/usr/local/src/torch*.whl') }}"
|
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
#
|
#
|
||||||
# pwngrid, bettercap
|
# pwngrid, bettercap
|
||||||
@ -359,14 +373,14 @@
|
|||||||
|
|
||||||
- name: Install go-1.21
|
- name: Install go-1.21
|
||||||
unarchive:
|
unarchive:
|
||||||
src: https://go.dev/dl/go1.21.6.linux-armv6l.tar.gz
|
src: https://go.dev/dl/go1.22.3.linux-armv6l.tar.gz
|
||||||
dest: /usr/local
|
dest: /usr/local
|
||||||
remote_src: yes
|
remote_src: yes
|
||||||
register: golang
|
register: golang
|
||||||
|
|
||||||
- name: Update .bashrc for go-1.21
|
- name: Update .bashrc for go-1.21
|
||||||
blockinfile:
|
blockinfile:
|
||||||
dest: /home/pi/.bashrc
|
dest: /etc/profile
|
||||||
state: present
|
state: present
|
||||||
block: |
|
block: |
|
||||||
export GOPATH=$HOME/go
|
export GOPATH=$HOME/go
|
||||||
@ -374,25 +388,42 @@
|
|||||||
when: golang.changed
|
when: golang.changed
|
||||||
|
|
||||||
- name: download pwngrid
|
- name: download pwngrid
|
||||||
unarchive:
|
git:
|
||||||
remote_src: yes
|
repo: "{{ packages.pwngrid.source }}"
|
||||||
src: "{{ packages.opwngrid.url }}"
|
dest: /usr/local/src/pwngrid
|
||||||
dest: /usr/local/bin/
|
|
||||||
mode: 0755
|
|
||||||
|
|
||||||
- name: download and install bettercap
|
- name: install pwngrid
|
||||||
unarchive:
|
shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && go mod tidy && make && make install"
|
||||||
src: "{{ packages.bettercap.url }}"
|
args:
|
||||||
dest: /usr/local/bin
|
executable: /bin/bash
|
||||||
remote_src: yes
|
chdir: /usr/local/src/pwngrid
|
||||||
exclude:
|
|
||||||
- README.md
|
- name: remove pwngrid folder
|
||||||
- LICENSE.md
|
file:
|
||||||
mode: 0755
|
state: absent
|
||||||
|
path: /usr/local/src/pwngrid
|
||||||
|
|
||||||
|
- name: download bettercap
|
||||||
|
git:
|
||||||
|
repo: "{{ packages.bettercap.source }}"
|
||||||
|
version: "{{ packages.bettercap.branch }} "
|
||||||
|
dest: /usr/local/src/bettercap
|
||||||
|
|
||||||
|
- name: install bettercap 2.32.4
|
||||||
|
shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && go mod tidy && make && make install"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/bettercap
|
||||||
|
|
||||||
|
- name: remove bettercap folder
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/bettercap
|
||||||
|
|
||||||
- name: clone bettercap caplets
|
- name: clone bettercap caplets
|
||||||
git:
|
git:
|
||||||
repo: "{{ packages.caplets.source }}"
|
repo: "{{ packages.caplets.source }}"
|
||||||
|
version: "{{ packages.caplets.branch }}"
|
||||||
dest: /tmp/caplets
|
dest: /tmp/caplets
|
||||||
register: capletsgit
|
register: capletsgit
|
||||||
|
|
||||||
@ -402,31 +433,11 @@
|
|||||||
target: install
|
target: install
|
||||||
when: capletsgit.changed
|
when: capletsgit.changed
|
||||||
|
|
||||||
- name: download and install bettercap ui
|
|
||||||
unarchive:
|
|
||||||
src: "{{ packages.bettercap.ui }}"
|
|
||||||
dest: /usr/local/share/bettercap/
|
|
||||||
remote_src: yes
|
|
||||||
mode: 0755
|
|
||||||
|
|
||||||
# to always have the bettercap webui available (because why not?)
|
|
||||||
- name: copy pwnagotchi-manual over pwnagotchi-auto caplet
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: /usr/local/share/bettercap/caplets/pwnagotchi-manual.cap
|
|
||||||
dest: /usr/local/share/bettercap/caplets/pwnagotchi-auto.cap
|
|
||||||
force: true
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: create /etc/pwnagotchi folder
|
- name: create /etc/pwnagotchi folder
|
||||||
file:
|
file:
|
||||||
path: /etc/pwnagotchi
|
path: /etc/pwnagotchi
|
||||||
state: directory
|
state: directory
|
||||||
|
|
||||||
- name: create log folder
|
|
||||||
file:
|
|
||||||
path: /home/pi/logs
|
|
||||||
state: directory
|
|
||||||
|
|
||||||
- name: check if user configuration exists
|
- name: check if user configuration exists
|
||||||
stat:
|
stat:
|
||||||
path: /etc/pwnagotchi/config.toml
|
path: /etc/pwnagotchi/config.toml
|
||||||
@ -442,32 +453,16 @@
|
|||||||
# ui.display.type = "waveshare_4"
|
# ui.display.type = "waveshare_4"
|
||||||
when: not user_config.stat.exists
|
when: not user_config.stat.exists
|
||||||
|
|
||||||
|
- name: Delete motd
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /etc/motd
|
||||||
|
|
||||||
- name: Delete motd 10-uname
|
- name: Delete motd 10-uname
|
||||||
file:
|
file:
|
||||||
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/ssh
|
|
||||||
state: touch
|
|
||||||
|
|
||||||
- name: change root partition
|
|
||||||
replace:
|
|
||||||
dest: /boot/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 firmware packages to hold
|
- name: add firmware packages to hold
|
||||||
dpkg_selections:
|
dpkg_selections:
|
||||||
name: "{{ item }}"
|
name: "{{ item }}"
|
||||||
@ -487,16 +482,7 @@
|
|||||||
enabled: true
|
enabled: true
|
||||||
state: stopped
|
state: stopped
|
||||||
with_items: "{{ services.enable }}"
|
with_items: "{{ services.enable }}"
|
||||||
|
register: enabled
|
||||||
#- name: remove golang build libraries
|
|
||||||
# file:
|
|
||||||
# state: absent
|
|
||||||
# path: /root/go
|
|
||||||
|
|
||||||
#- name: remove golang
|
|
||||||
# file:
|
|
||||||
# state: absent
|
|
||||||
# path: /usr/local/go
|
|
||||||
|
|
||||||
- name: make /root readable, becauase that's where all the files are
|
- name: make /root readable, becauase that's where all the files are
|
||||||
file:
|
file:
|
||||||
@ -510,53 +496,58 @@
|
|||||||
group: pi
|
group: pi
|
||||||
recurse: true
|
recurse: true
|
||||||
|
|
||||||
- name: remove unnecessary apt packages
|
|
||||||
apt:
|
|
||||||
name: "{{ packages.apt.remove }}"
|
|
||||||
state: absent
|
|
||||||
purge: yes
|
|
||||||
|
|
||||||
- name: remove dependencies that are no longer required
|
|
||||||
apt:
|
|
||||||
autoremove: yes
|
|
||||||
|
|
||||||
- name: clean apt cache
|
|
||||||
apt:
|
|
||||||
autoclean: true
|
|
||||||
|
|
||||||
- name: remove golang build libraries
|
|
||||||
file:
|
|
||||||
state: absent
|
|
||||||
path: /root/go
|
|
||||||
|
|
||||||
- name: remove pre-collected packages zip
|
- name: remove pre-collected packages zip
|
||||||
file:
|
file:
|
||||||
path: /root/go_pkgs.tgz
|
path: /root/go_pkgs.tgz
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: remove golang
|
- name: remove /root/go folder
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /root/go
|
||||||
|
|
||||||
|
- name: remove /usr/local/go folder
|
||||||
file:
|
file:
|
||||||
state: absent
|
state: absent
|
||||||
path: /usr/local/go
|
path: /usr/local/go
|
||||||
|
|
||||||
- name: remove /root/.cache (pip cache)
|
- name: remove pip cache
|
||||||
file:
|
file:
|
||||||
state: absent
|
state: absent
|
||||||
path: /root/.cache
|
path: /root/.cache/pip
|
||||||
|
|
||||||
- name: remove ssh keys
|
- name: remove ssh keys
|
||||||
file:
|
file:
|
||||||
state: absent
|
state: absent
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
with_fileglob:
|
with_fileglob:
|
||||||
- "/etc/ssh/ssh_host*_key*"
|
- "/etc/ssh/ssh_host*_key*"
|
||||||
|
|
||||||
- name: regenerate ssh keys
|
- name: regenerate ssh keys
|
||||||
shell: "dpkg-reconfigure openssh-server"
|
shell: "dpkg-reconfigure openssh-server"
|
||||||
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:
|
||||||
daemon_reload: yes
|
daemon_reload: yes
|
||||||
|
when: enabled.changed
|
@ -1,8 +1,8 @@
|
|||||||
packer {
|
packer {
|
||||||
required_plugins {
|
required_plugins {
|
||||||
arm = {
|
arm = {
|
||||||
version = "1.0.0"
|
version = ">=1.0.0"
|
||||||
source = "github.com/cdecoux/builder-arm"
|
source = "github.com/michalfita/cross"
|
||||||
}
|
}
|
||||||
ansible = {
|
ansible = {
|
||||||
source = "github.com/hashicorp/ansible"
|
source = "github.com/hashicorp/ansible"
|
||||||
@ -73,7 +73,13 @@ build {
|
|||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
inline = ["chmod +x /usr/bin/*"]
|
inline = ["chmod +x /usr/bin/*"]
|
||||||
}
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["mkdir -p /usr/local/src/pwnagotchi"]
|
||||||
|
}
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/usr/local/src/pwnagotchi/"
|
||||||
|
source = "../"
|
||||||
|
}
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/etc/systemd/system/"
|
destination = "/etc/systemd/system/"
|
||||||
sources = [
|
sources = [
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
vars:
|
vars:
|
||||||
kernel:
|
kernel:
|
||||||
min: "6.6"
|
min: "6.6"
|
||||||
full: "6.6.20+rpt-rpi-v8"
|
full: "6.6.31+rpt-rpi-v8"
|
||||||
full_pi5: "6.6.20+rpt-rpi-2712"
|
full_pi5: "6.6.31+rpt-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', true) }}"
|
version: "{{ lookup('env', 'PWN_VERSION') | default('pwnagotchi', true) }}"
|
||||||
@ -27,10 +27,11 @@
|
|||||||
packages:
|
packages:
|
||||||
caplets:
|
caplets:
|
||||||
source: "https://github.com/jayofelony/caplets.git"
|
source: "https://github.com/jayofelony/caplets.git"
|
||||||
|
branch: "lite" # or master
|
||||||
bettercap:
|
bettercap:
|
||||||
source: "https://github.com/jayofelony/bettercap.git"
|
source: "https://github.com/jayofelony/bettercap.git"
|
||||||
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.4/bettercap-2.32.4.zip"
|
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.4/bettercap-2.32.4.zip"
|
||||||
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
|
branch: "lite" # or master
|
||||||
pwngrid:
|
pwngrid:
|
||||||
source: "https://github.com/jayofelony/pwngrid.git"
|
source: "https://github.com/jayofelony/pwngrid.git"
|
||||||
url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.5/pwngrid-1.10.5-aarch64.zip"
|
url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.5/pwngrid-1.10.5-aarch64.zip"
|
||||||
@ -51,23 +52,18 @@
|
|||||||
- libpcap0.8-dbg
|
- libpcap0.8-dbg
|
||||||
- libpcap0.8-dev
|
- libpcap0.8-dev
|
||||||
remove:
|
remove:
|
||||||
- avahi-daemon
|
|
||||||
- dhpys-swapfile
|
- dhpys-swapfile
|
||||||
- libcurl-ocaml-dev
|
|
||||||
- libssl-ocaml-dev
|
|
||||||
- nfs-common
|
- nfs-common
|
||||||
- triggerhappy
|
- triggerhappy
|
||||||
- wpasupplicant
|
- wpasupplicant
|
||||||
install:
|
install:
|
||||||
- aircrack-ng
|
- aircrack-ng
|
||||||
- autoconf
|
- autoconf
|
||||||
- bc
|
|
||||||
- bison
|
- bison
|
||||||
- bluez
|
- bluez
|
||||||
- bluez-tools
|
- bluez-tools
|
||||||
- build-essential
|
- build-essential
|
||||||
- curl
|
- curl
|
||||||
- dkms
|
|
||||||
- dphys-swapfile
|
- dphys-swapfile
|
||||||
- fbi
|
- fbi
|
||||||
- firmware-atheros
|
- firmware-atheros
|
||||||
@ -76,86 +72,38 @@
|
|||||||
- firmware-misc-nonfree
|
- firmware-misc-nonfree
|
||||||
- firmware-realtek
|
- firmware-realtek
|
||||||
- flex
|
- flex
|
||||||
- fonts-dejavu
|
|
||||||
- fonts-dejavu-core
|
|
||||||
- fonts-dejavu-extra
|
|
||||||
- fonts-freefont-ttf
|
|
||||||
- g++
|
- g++
|
||||||
- gawk
|
- gawk
|
||||||
- gcc-arm-none-eabi
|
- gcc-arm-none-eabi
|
||||||
- git
|
- git
|
||||||
- hcxtools
|
|
||||||
- libatlas-base-dev
|
|
||||||
- libavcodec59
|
|
||||||
- libavformat59
|
|
||||||
- libblas-dev
|
|
||||||
- libbluetooth-dev
|
|
||||||
- libbz2-dev
|
|
||||||
- libc-ares-dev
|
|
||||||
- libc6-dev
|
- libc6-dev
|
||||||
- libcap-dev
|
|
||||||
- libcurl-ocaml-dev
|
- libcurl-ocaml-dev
|
||||||
- libdbus-1-dev
|
- libdbus-1-dev
|
||||||
- libdbus-glib-1-dev
|
- libdbus-glib-1-dev
|
||||||
- libeigen3-dev
|
|
||||||
- libelf-dev
|
|
||||||
- libffi-dev
|
|
||||||
- libfl-dev
|
- libfl-dev
|
||||||
- libfuse-dev
|
|
||||||
- libgdbm-dev
|
|
||||||
- libgl1-mesa-glx
|
|
||||||
- libgmp3-dev
|
- libgmp3-dev
|
||||||
- libgstreamer1.0-0
|
|
||||||
- libhdf5-dev
|
|
||||||
- liblapack-dev
|
|
||||||
- libncursesw5-dev
|
|
||||||
- libnetfilter-queue-dev
|
- libnetfilter-queue-dev
|
||||||
- libopenblas-dev
|
|
||||||
- libopenjp2-7
|
|
||||||
- libopenmpi-dev
|
|
||||||
- libopenmpi3
|
|
||||||
- libpcap-dev
|
- libpcap-dev
|
||||||
- libraspberrypi-bin
|
- libraspberrypi-bin
|
||||||
- libraspberrypi-dev
|
- libraspberrypi-dev
|
||||||
- libraspberrypi-doc
|
- libraspberrypi-doc
|
||||||
- libraspberrypi0
|
- libraspberrypi0
|
||||||
- libsqlite3-dev
|
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
- libssl-ocaml-dev
|
- libssl-ocaml-dev
|
||||||
- libswscale5
|
|
||||||
- libtiff6
|
|
||||||
- libtool
|
- libtool
|
||||||
- libusb-1.0-0-dev
|
- libusb-1.0-0-dev
|
||||||
- lsof
|
|
||||||
- make
|
- make
|
||||||
- ntp
|
- ntp
|
||||||
- python3-dbus
|
- pkg-config
|
||||||
- python3-flask
|
- python3-dev
|
||||||
- python3-flask-cors
|
|
||||||
- python3-flaskext.wtf
|
|
||||||
- python3-gast
|
|
||||||
- python3-pil
|
|
||||||
- python3-pip
|
- python3-pip
|
||||||
- python3-pycryptodome
|
|
||||||
- python3-requests
|
|
||||||
- python3-scapy
|
|
||||||
- python3-setuptools
|
- python3-setuptools
|
||||||
- python3-smbus
|
|
||||||
- python3-smbus2
|
|
||||||
- python3-spidev
|
|
||||||
- python3-tweepy
|
|
||||||
- python3-werkzeug
|
|
||||||
- python3-yaml
|
|
||||||
- qpdf
|
- qpdf
|
||||||
- raspberrypi-kernel-headers
|
- raspberrypi-kernel-headers
|
||||||
- rsync
|
- rsync
|
||||||
- screen
|
|
||||||
- tcpdump
|
- tcpdump
|
||||||
- texinfo
|
- texinfo
|
||||||
- time
|
|
||||||
- tk-dev
|
|
||||||
- unzip
|
- unzip
|
||||||
- vim
|
|
||||||
- wget
|
- wget
|
||||||
- wl
|
- wl
|
||||||
- xxd
|
- xxd
|
||||||
@ -168,9 +116,9 @@
|
|||||||
- name: install packages
|
- name: install packages
|
||||||
apt:
|
apt:
|
||||||
name: "{{ packages.apt.install }}"
|
name: "{{ packages.apt.install }}"
|
||||||
state: present
|
state: latest
|
||||||
update_cache: yes
|
update_cache: yes
|
||||||
install_recommends: false
|
install_recommends: no
|
||||||
|
|
||||||
- name: update pip3, setuptools, wheel
|
- name: update pip3, setuptools, wheel
|
||||||
shell: "python3 -m pip install --upgrade pip setuptools wheel --break-system-packages"
|
shell: "python3 -m pip install --upgrade pip setuptools wheel --break-system-packages"
|
||||||
@ -178,12 +126,22 @@
|
|||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
chdir: /usr/local/src
|
chdir: /usr/local/src
|
||||||
|
|
||||||
|
- name: build pwnagotchi wheel
|
||||||
|
command: "pip3 install . --no-cache-dir --break-system-packages"
|
||||||
|
args:
|
||||||
|
chdir: /usr/local/src/pwnagotchi
|
||||||
|
|
||||||
|
- name: remove pwnagotchi folder
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/pwnagotchi
|
||||||
|
|
||||||
# Now we set up /boot/firmware
|
# 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:$5$733Efsksay$SEFUKemv8FaNAu6X4GUfxdSzSDh6PbpOcdtNe5b7Nt0
|
||||||
|
|
||||||
- name: enable ssh on boot
|
- name: enable ssh on boot
|
||||||
file:
|
file:
|
||||||
@ -211,6 +169,35 @@
|
|||||||
regexp: '(.*)$'
|
regexp: '(.*)$'
|
||||||
line: '\1 modules-load=dwc2,g_ether'
|
line: '\1 modules-load=dwc2,g_ether'
|
||||||
|
|
||||||
|
- name: setup /boot/firmware/config.txt
|
||||||
|
blockinfile:
|
||||||
|
path: /boot/firmware/config.txt
|
||||||
|
insertafter: EOF
|
||||||
|
block: |
|
||||||
|
dtparam=i2c1=on
|
||||||
|
dtparam=i2c_arm=on
|
||||||
|
dtparam=spi=on
|
||||||
|
gpu_mem=1
|
||||||
|
dtoverlay=dwc2
|
||||||
|
#dtoverlay=disable-wifi
|
||||||
|
enable_uart=1
|
||||||
|
|
||||||
|
[pi0]
|
||||||
|
dtoverlay=spi0-0cs
|
||||||
|
#dtoverlay=disable-wifi
|
||||||
|
|
||||||
|
[pi3]
|
||||||
|
dtoverlay=spi0-0cs
|
||||||
|
#dtoverlay=disable-wifi
|
||||||
|
|
||||||
|
[pi4]
|
||||||
|
dtoverlay=spi0-0cs
|
||||||
|
#dtoverlay=disable-wifi
|
||||||
|
|
||||||
|
[pi5]
|
||||||
|
dtoverlay=spi0-0cs
|
||||||
|
#dtoverlay=disable-wifi
|
||||||
|
|
||||||
- name: change hostname
|
- name: change hostname
|
||||||
lineinfile:
|
lineinfile:
|
||||||
dest: /etc/hostname
|
dest: /etc/hostname
|
||||||
@ -270,7 +257,6 @@
|
|||||||
state: link
|
state: link
|
||||||
|
|
||||||
# install latest hcxtools
|
# install latest hcxtools
|
||||||
|
|
||||||
- name: clone hcxtools
|
- name: clone hcxtools
|
||||||
git:
|
git:
|
||||||
repo: https://github.com/ZerBea/hcxtools.git
|
repo: https://github.com/ZerBea/hcxtools.git
|
||||||
@ -287,13 +273,13 @@
|
|||||||
state: absent
|
state: absent
|
||||||
path: /usr/local/src/hcxtools
|
path: /usr/local/src/hcxtools
|
||||||
|
|
||||||
|
# Installing nexmon
|
||||||
- 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
|
||||||
|
|
||||||
# FIRST WE BUILD DRIVER FOR RPi5
|
# FIRST WE BUILD DRIVER FOR RPi5
|
||||||
|
|
||||||
- name: make firmware, RPi5
|
- name: make firmware, RPi5
|
||||||
shell: "source ./setup_env.sh && make"
|
shell: "source ./setup_env.sh && make"
|
||||||
args:
|
args:
|
||||||
@ -320,11 +306,6 @@
|
|||||||
QEMU_UNAME: "{{ kernel.full_pi5 }}"
|
QEMU_UNAME: "{{ kernel.full_pi5 }}"
|
||||||
ARCHFLAGS: "-arch aarch64"
|
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
|
- 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"
|
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"
|
||||||
|
|
||||||
@ -339,7 +320,6 @@
|
|||||||
path: /usr/local/src/nexmon/
|
path: /usr/local/src/nexmon/
|
||||||
|
|
||||||
# NOW WE BUILD DRIVERS FOR RPi4, RPizero2w and RPi3
|
# NOW WE BUILD DRIVERS FOR RPi4, RPizero2w and RPi3
|
||||||
|
|
||||||
- name: clone nexmon repository
|
- name: clone nexmon repository
|
||||||
git:
|
git:
|
||||||
repo: https://github.com/DrSchottky/nexmon.git
|
repo: https://github.com/DrSchottky/nexmon.git
|
||||||
@ -370,7 +350,6 @@
|
|||||||
follow: true
|
follow: true
|
||||||
|
|
||||||
# NOW WE BUILD DRIVERS FOR RPiZero2W, RPi 3
|
# 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:
|
||||||
@ -395,6 +374,12 @@
|
|||||||
QEMU_UNAME: "{{ kernel.full }}"
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
ARCHFLAGS: "-arch aarch64"
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
|
- name: install new firmware (bcm43430a1)
|
||||||
|
copy:
|
||||||
|
src: /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/brcmfmac43430-sdio.bin
|
||||||
|
dest: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
||||||
|
follow: true
|
||||||
|
|
||||||
- name: copy modified driver, RPi4
|
- name: copy modified driver, RPi4
|
||||||
copy:
|
copy:
|
||||||
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
|
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
|
||||||
@ -403,12 +388,6 @@
|
|||||||
QEMU_UNAME: "{{ kernel.full }}"
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
ARCHFLAGS: "-arch aarch64"
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
- name: install new firmware (bcm43430a1)
|
|
||||||
copy:
|
|
||||||
src: /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/brcmfmac43430-sdio.bin
|
|
||||||
dest: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
|
||||||
follow: true
|
|
||||||
|
|
||||||
- name: copy 43430-sdio as 43436s-sdio for the special 43430/1 /2
|
- name: copy 43430-sdio as 43436s-sdio for the special 43430/1 /2
|
||||||
copy:
|
copy:
|
||||||
src: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
src: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
||||||
@ -428,6 +407,7 @@
|
|||||||
- /usr/lib/firmware/brcm/brcmfmac43436-sdio.clm_blob
|
- /usr/lib/firmware/brcm/brcmfmac43436-sdio.clm_blob
|
||||||
- /usr/lib/firmware/brcm/brcmfmac43436-sdio.raspberrypi,model-zero-2-w.clm_blob
|
- /usr/lib/firmware/brcm/brcmfmac43436-sdio.raspberrypi,model-zero-2-w.clm_blob
|
||||||
- /usr/lib/firmware/brcm/brcmfmac43455-sdio.clm_blob
|
- /usr/lib/firmware/brcm/brcmfmac43455-sdio.clm_blob
|
||||||
|
- /usr/lib/firmware/brcm/BCM43430A1.raspberrypi,model-zero-2-w.hcd
|
||||||
|
|
||||||
- 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"
|
||||||
@ -443,39 +423,24 @@
|
|||||||
state: absent
|
state: absent
|
||||||
path: /usr/local/src/nexmon/
|
path: /usr/local/src/nexmon/
|
||||||
|
|
||||||
- name: Create custom plugin directory
|
|
||||||
file:
|
|
||||||
path: /usr/local/share/pwnagotchi/custom-plugins/
|
|
||||||
state: directory
|
|
||||||
|
|
||||||
- name: Create custom config directory
|
- name: Create custom config directory
|
||||||
file:
|
file:
|
||||||
path: /etc/pwnagotchi/conf.d/
|
path: /etc/pwnagotchi/conf.d/
|
||||||
state: directory
|
state: directory
|
||||||
|
|
||||||
- name: clone pwnagotchi repository
|
|
||||||
git:
|
|
||||||
repo: https://github.com/jayofelony/pwnagotchi.git
|
|
||||||
dest: /usr/local/src/pwnagotchi
|
|
||||||
|
|
||||||
- name: build pwnagotchi wheel
|
|
||||||
command: "pip3 install . --no-cache-dir --break-system-packages"
|
|
||||||
args:
|
|
||||||
chdir: /usr/local/src/pwnagotchi
|
|
||||||
|
|
||||||
- name: remove pwnagotchi folder
|
|
||||||
file:
|
|
||||||
state: absent
|
|
||||||
path: /usr/local/src/pwnagotchi
|
|
||||||
|
|
||||||
- name: create /usr/local/share/pwnagotchi/ folder
|
- name: create /usr/local/share/pwnagotchi/ folder
|
||||||
file:
|
file:
|
||||||
path: /usr/local/share/pwnagotchi/
|
path: /usr/local/share/pwnagotchi/
|
||||||
state: directory
|
state: directory
|
||||||
|
|
||||||
|
- name: Create custom plugin directory
|
||||||
|
file:
|
||||||
|
path: /usr/local/share/pwnagotchi/custom-plugins/
|
||||||
|
state: directory
|
||||||
|
|
||||||
- name: Install go-1.21
|
- name: Install go-1.21
|
||||||
unarchive:
|
unarchive:
|
||||||
src: https://go.dev/dl/go1.21.5.linux-arm64.tar.gz
|
src: https://go.dev/dl/go1.22.3.linux-arm64.tar.gz
|
||||||
dest: /usr/local
|
dest: /usr/local
|
||||||
remote_src: yes
|
remote_src: yes
|
||||||
register: golang
|
register: golang
|
||||||
@ -508,6 +473,7 @@
|
|||||||
- name: download bettercap
|
- name: download bettercap
|
||||||
git:
|
git:
|
||||||
repo: "{{ packages.bettercap.source }}"
|
repo: "{{ packages.bettercap.source }}"
|
||||||
|
version: "{{ packages.bettercap.branch }}"
|
||||||
dest: /usr/local/src/bettercap
|
dest: /usr/local/src/bettercap
|
||||||
|
|
||||||
- name: install bettercap 2.32.4
|
- name: install bettercap 2.32.4
|
||||||
@ -534,6 +500,7 @@
|
|||||||
- name: clone bettercap caplets
|
- name: clone bettercap caplets
|
||||||
git:
|
git:
|
||||||
repo: "{{ packages.caplets.source }}"
|
repo: "{{ packages.caplets.source }}"
|
||||||
|
version: "{{ packages.caplets.branch }}"
|
||||||
dest: /tmp/caplets
|
dest: /tmp/caplets
|
||||||
register: capletsgit
|
register: capletsgit
|
||||||
|
|
||||||
@ -543,21 +510,6 @@
|
|||||||
target: install
|
target: install
|
||||||
when: capletsgit.changed
|
when: capletsgit.changed
|
||||||
|
|
||||||
- name: download and install bettercap ui
|
|
||||||
unarchive:
|
|
||||||
src: "{{ packages.bettercap.ui }}"
|
|
||||||
dest: /usr/local/share/bettercap/
|
|
||||||
remote_src: yes
|
|
||||||
mode: 0755
|
|
||||||
|
|
||||||
# to always have the bettercap webui available (because why not?)
|
|
||||||
- name: copy pwnagotchi-manual over pwnagotchi-auto caplet
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: /usr/local/share/bettercap/caplets/pwnagotchi-manual.cap
|
|
||||||
dest: /usr/local/share/bettercap/caplets/pwnagotchi-auto.cap
|
|
||||||
force: true
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: create /etc/pwnagotchi folder
|
- name: create /etc/pwnagotchi folder
|
||||||
file:
|
file:
|
||||||
path: /etc/pwnagotchi
|
path: /etc/pwnagotchi
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = '2.8.9'
|
__version__ = '2.9.2'
|
||||||
|
@ -150,8 +150,6 @@ personality.bond_encounters_factor = 20000
|
|||||||
personality.throttle_a = 0.4
|
personality.throttle_a = 0.4
|
||||||
personality.throttle_d = 0.9
|
personality.throttle_d = 0.9
|
||||||
|
|
||||||
personality.clear_on_exit = true # clear display when shutting down cleanly
|
|
||||||
|
|
||||||
ui.invert = false # false = black background, true = white background
|
ui.invert = false # false = black background, true = white background
|
||||||
|
|
||||||
ui.fps = 0.0
|
ui.fps = 0.0
|
||||||
|
Binary file not shown.
@ -1,260 +1,260 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
# pwnagotchi Brazilian Portuguese translation file.
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
# Copyright (C) 2024
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the pwnagotchi package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# Fabiano F O <fabfernandes@hotmail.com>, 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-17 15:46+0100\n"
|
"POT-Creation-Date: 2024-03-25 22:30+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Foxy <EMAIL@ADDRESS>\n"
|
"Last-Translator: Fabiano F O <fabfernandes@hotmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: Portuguese (Brazil)\n"
|
"Language: Brazilian Portuguese\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
msgid "ZzzzZZzzzzZzzz"
|
msgid "ZzzzZZzzzzZzzz"
|
||||||
msgstr "ZzzzZZzzzzZzzz"
|
msgstr "ZzzzZZzzzzZzzz"
|
||||||
|
|
||||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||||
msgstr "Olá, Eu sou Pwnagotchi! Iniciando ..."
|
msgstr "Olá, sou Pwnagotchi! Iniciando ..."
|
||||||
|
|
||||||
msgid "New day, new hunt, new pwns!"
|
msgid "New day, new hunt, new pwns!"
|
||||||
msgstr "Um novo dia, Uma nova caça e novos pwns!"
|
msgstr "Novo dia, Nova caçada, Novos pwns!"
|
||||||
|
|
||||||
msgid "Hack the Planet!"
|
msgid "Hack the Planet!"
|
||||||
msgstr "Burle o Planeta!"
|
msgstr "Hackeie o Planeta!"
|
||||||
|
|
||||||
msgid "AI ready."
|
msgid "AI ready."
|
||||||
msgstr "IA pronta."
|
msgstr "IA pronta."
|
||||||
|
|
||||||
msgid "The neural network is ready."
|
msgid "The neural network is ready."
|
||||||
msgstr "A rede neural está pronta."
|
msgstr "A rede neural está pronta."
|
||||||
|
|
||||||
msgid "Generating keys, do not turn off ..."
|
msgid "Generating keys, do not turn off ..."
|
||||||
msgstr "Criando chaves, não desligue o sistema ..."
|
msgstr "Gerando chaves, não desligue ..."
|
||||||
|
|
||||||
#, 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 "Ei, canal {channel} está livre! Seu AP vai agradecer."
|
msgstr "Ei, o canal {channel} está livre! Seu AP vai agradecer."
|
||||||
|
|
||||||
msgid "Reading last session logs ..."
|
msgid "Reading last session logs ..."
|
||||||
msgstr "Lendo os logs da ultima sessão"
|
msgstr "Lendo os logs da última 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 "Leia {lines_so_far} linha de logs até agora ..."
|
msgstr "Li {lines_so_far} linhas de logs até agora ..."
|
||||||
|
|
||||||
msgid "I'm bored ..."
|
msgid "I'm bored ..."
|
||||||
msgstr "Eu estou entediado ..."
|
msgstr "Estou entediado ..."
|
||||||
|
|
||||||
msgid "Let's go for a walk!"
|
msgid "Let's go for a walk!"
|
||||||
msgstr "Vamos ir numa caminhada!"
|
msgstr "Vamos dar um passeio!"
|
||||||
|
|
||||||
msgid "This is the best day of my life!"
|
msgid "This is the best day of my life!"
|
||||||
msgstr "Esse é o melhor dia da minha vida!"
|
msgstr "Este é o melhor dia da minha vida!"
|
||||||
|
|
||||||
msgid "Shitty day :/"
|
msgid "Shitty day :/"
|
||||||
msgstr "Dia ruim :/"
|
msgstr "Que dia ruim :/"
|
||||||
|
|
||||||
msgid "I'm extremely bored ..."
|
msgid "I'm extremely bored ..."
|
||||||
msgstr "Eu estou extremamente entediado ..."
|
msgstr "Estou extremamente entediado ..."
|
||||||
|
|
||||||
msgid "I'm very sad ..."
|
msgid "I'm very sad ..."
|
||||||
msgstr "Eu estou muito triste ..."
|
msgstr "Estou muito triste ..."
|
||||||
|
|
||||||
msgid "I'm sad"
|
msgid "I'm sad"
|
||||||
msgstr "Eu estou triste"
|
msgstr "Estou triste"
|
||||||
|
|
||||||
msgid "Leave me alone ..."
|
msgid "Leave me alone ..."
|
||||||
msgstr "Me deixe em paz ..."
|
msgstr "Me deixe em paz ..."
|
||||||
|
|
||||||
msgid "I'm mad at you!"
|
msgid "I'm mad at you!"
|
||||||
msgstr "Eu estou bravo com você!"
|
msgstr "Estou bravo com você!"
|
||||||
|
|
||||||
msgid "I'm living the life!"
|
msgid "I'm living the life!"
|
||||||
msgstr "Eu estou vivendo a vida!"
|
msgstr "Estou aproveitando a vida!"
|
||||||
|
|
||||||
msgid "I pwn therefore I am."
|
msgid "I pwn therefore I am."
|
||||||
msgstr "Eu pwn então Eu sou."
|
msgstr "Eu pwn, logo existo."
|
||||||
|
|
||||||
msgid "So many networks!!!"
|
msgid "So many networks!!!"
|
||||||
msgstr "Tantas redes!!!"
|
msgstr "Uau! Quantas redes!!"
|
||||||
|
|
||||||
msgid "I'm having so much fun!"
|
msgid "I'm having so much fun!"
|
||||||
msgstr "Eu estou tendo muita diversão"
|
msgstr "Estou me divertindo muito!"
|
||||||
|
|
||||||
msgid "My crime is that of curiosity ..."
|
msgid "My crime is that of curiosity ..."
|
||||||
msgstr "Meu crime é de curiosidade ..."
|
msgstr "Meu crime é a curiosidade ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hello {name}! Nice to meet you."
|
msgid "Hello {name}! Nice to meet you."
|
||||||
msgstr "Olá {name}! É bom em conhecê-lo"
|
msgstr "Olá {name}! Prazer em conhecê-lo."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Yo {name}! Sup?"
|
msgid "Yo {name}! Sup?"
|
||||||
msgstr "Ei {name}! Como vai?"
|
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 "Ei {name} como você está indo?"
|
msgstr "Ei {name}, como você está?"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Unit {name} is nearby!"
|
msgid "Unit {name} is nearby!"
|
||||||
msgstr ""
|
msgstr "A unidade {name} está próxima!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uhm ... goodbye {name}"
|
msgid "Uhm ... goodbye {name}"
|
||||||
msgstr ""
|
msgstr "Hmm ... tchau {name}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} is gone ..."
|
msgid "{name} is gone ..."
|
||||||
msgstr ""
|
msgstr "{name} desapareceu ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Whoops ... {name} is gone."
|
msgid "Whoops ... {name} is gone."
|
||||||
msgstr ""
|
msgstr "Oops ... {name} desapareceu."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} missed!"
|
msgid "{name} missed!"
|
||||||
msgstr "{name} errou!"
|
msgstr "Perdi {name}!"
|
||||||
|
|
||||||
msgid "Missed!"
|
msgid "Missed!"
|
||||||
msgstr "Errei!"
|
msgstr "Perdi!"
|
||||||
|
|
||||||
msgid "Good friends are a blessing!"
|
msgid "Good friends are a blessing!"
|
||||||
msgstr "Bom amigos são uma bensão!"
|
msgstr "Bons amigos são uma bênção!"
|
||||||
|
|
||||||
msgid "I love my friends!"
|
msgid "I love my friends!"
|
||||||
msgstr "Eu amo meus amigos!"
|
msgstr "Eu amo meus amigos!"
|
||||||
|
|
||||||
msgid "Nobody wants to play with me ..."
|
msgid "Nobody wants to play with me ..."
|
||||||
msgstr "Ninguém quer brincar comigo ..."
|
msgstr "Ninguém quer brincar comigo ..."
|
||||||
|
|
||||||
msgid "I feel so alone ..."
|
msgid "I feel so alone ..."
|
||||||
msgstr "Estou me sentindo sozinho"
|
msgstr "Me sinto tão sozinho ..."
|
||||||
|
|
||||||
msgid "Where's everybody?!"
|
msgid "Where's everybody?!"
|
||||||
msgstr "Onde está todo mundo?!"
|
msgstr "Onde está todo mundo?!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Napping for {secs}s ..."
|
msgid "Napping for {secs}s ..."
|
||||||
msgstr "Tirando uma soneca por {secs}s ..."
|
msgstr "Tirando uma soneca por {secs}s ..."
|
||||||
|
|
||||||
msgid "Zzzzz"
|
msgid "Zzzzz"
|
||||||
msgstr "Zzzzz"
|
msgstr "Zzzzz"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "ZzzZzzz ({secs}s)"
|
msgid "ZzzZzzz ({secs}s)"
|
||||||
msgstr "ZzzZzzz ({secs}s)"
|
msgstr "ZzzZzzz ({secs}s)"
|
||||||
|
|
||||||
msgid "Good night."
|
msgid "Good night."
|
||||||
msgstr "Boa noite."
|
msgstr "Boa noite."
|
||||||
|
|
||||||
msgid "Zzz"
|
msgid "Zzz"
|
||||||
msgstr "Zzz"
|
msgstr "Zzz"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Waiting for {secs}s ..."
|
msgid "Waiting for {secs}s ..."
|
||||||
msgstr "Esperando por {secs}s ..."
|
msgstr "Aguardando {secs}s ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Looking around ({secs}s)"
|
msgid "Looking around ({secs}s)"
|
||||||
msgstr "Olhando por volta ({secs}s)"
|
msgstr "Olhando em volta ... ({secs}s)"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey {what} let's be friends!"
|
msgid "Hey {what} let's be friends!"
|
||||||
msgstr "Ei {what} vamos ser amigos!"
|
msgstr "Ei {what}, vamos ser amigos!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Associating to {what}"
|
msgid "Associating to {what}"
|
||||||
msgstr "Associando para {what}"
|
msgstr "Associando a {what}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Yo {what}!"
|
msgid "Yo {what}!"
|
||||||
msgstr "Ei {what}!"
|
msgstr "Olá {what}!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Just decided that {mac} needs no WiFi!"
|
msgid "Just decided that {mac} needs no WiFi!"
|
||||||
msgstr "Apenas decidindo que {mac} não precisa de WiFi!"
|
msgstr "Acabei de decidir que {mac} não precisa de WiFi!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Deauthenticating {mac}"
|
msgid "Deauthenticating {mac}"
|
||||||
msgstr "Desautenticando {mac}"
|
msgstr "Desautenticando {mac}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Kickbanning {mac}!"
|
msgid "Kickbanning {mac}!"
|
||||||
msgstr "Banindo {mac}!"
|
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 "Legal, conseguimos {num} novos handshake{plural}!"
|
msgstr "Legal, conseguimos {num} novo{plural} handshake{plural}!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "You have {count} new message{plural}!"
|
msgid "You have {count} new message{plural}!"
|
||||||
msgstr "Você tem {count} novas messagem{plural}!"
|
msgstr "Você tem {count} nova{plural} messagem{plural}!"
|
||||||
|
|
||||||
msgid "Oops, something went wrong ... Rebooting ..."
|
msgid "Oops, something went wrong ... Rebooting ..."
|
||||||
msgstr "Oops, algo deu errado ... Reiniciando ..."
|
msgstr "Oops, algo deu errado ... Reiniciando ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uploading data to {to} ..."
|
msgid "Uploading data to {to} ..."
|
||||||
msgstr "Enviando dados para {to} ..."
|
msgstr "Enviando dados para {to} ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Downloading from {name} ..."
|
msgid "Downloading from {name} ..."
|
||||||
msgstr "Instalando para {name} ..."
|
msgstr "Baixando de {name} ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Kicked {num} stations\n"
|
msgid "Kicked {num} stations\n"
|
||||||
msgstr "Expulsei {num} estações\n"
|
msgstr "Expulsei {num} estações\n"
|
||||||
|
|
||||||
msgid "Made >999 new friends\n"
|
msgid "Made >999 new friends\n"
|
||||||
msgstr "Fiz >999 novos amigos\n"
|
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 "Fiz {num} novos amigos\n"
|
msgstr "Fiz {num} novos amigos\n"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Got {num} handshakes\n"
|
msgid "Got {num} handshakes\n"
|
||||||
msgstr "Peguei {num} handshakes\n"
|
msgstr "Peguei {num} handshakes\n"
|
||||||
|
|
||||||
msgid "Met 1 peer"
|
msgid "Met 1 peer"
|
||||||
msgstr "Encontrei 1 pessoa"
|
msgstr "Conheci 1 peer"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Met {num} peers"
|
msgid "Met {num} peers"
|
||||||
msgstr "Encontrei {num} pessoas"
|
msgstr "Conheci {num} peers"
|
||||||
|
|
||||||
#, 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 ""
|
||||||
"Estou navegando há {duration} e expulsei {deauthed} clientes! Também conheci "
|
"Estou pwning há {duration} e expulsei {deauthed} clientes! Também conheci "
|
||||||
"{associamos} novos amigos e comi {handshakes} handshakes! #pwnagotchi "
|
"{associated} novos amigos e comi {handshakes} handshakes! #pwnagotchi "
|
||||||
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
||||||
|
|
||||||
msgid "hours"
|
msgid "hours"
|
||||||
msgstr "horas"
|
msgstr "horas"
|
||||||
|
|
||||||
msgid "minutes"
|
msgid "minutes"
|
||||||
msgstr "minutos"
|
msgstr "minutos"
|
||||||
|
|
||||||
msgid "seconds"
|
msgid "seconds"
|
||||||
msgstr "segundos"
|
msgstr "segundos"
|
||||||
|
|
||||||
msgid "hour"
|
msgid "hour"
|
||||||
msgstr "hora"
|
msgstr "hora"
|
||||||
|
|
||||||
msgid "minute"
|
msgid "minute"
|
||||||
msgstr "minuto"
|
msgstr "minuto"
|
||||||
|
|
||||||
msgid "second"
|
msgid "second"
|
||||||
msgstr "segundo"
|
msgstr "segundo"
|
BIN
pwnagotchi/locale/rs/LC_MESSAGES/voice.mo
Normal file
BIN
pwnagotchi/locale/rs/LC_MESSAGES/voice.mo
Normal file
Binary file not shown.
260
pwnagotchi/locale/rs/LC_MESSAGES/voice.po
Normal file
260
pwnagotchi/locale/rs/LC_MESSAGES/voice.po
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <dragan.miljkovic29@gmail.com>, 2024.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Srpski prevod v1\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2024-02-16 15:26-0300\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: RS <dragan.miljkovic29@gmail.com>\n"
|
||||||
|
"Language: Serbian\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
msgid "ZzzzZZzzzzZzzz"
|
||||||
|
msgstr "ZzzzZZzzzzZzzz"
|
||||||
|
|
||||||
|
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||||
|
msgstr "Zdravo, ja sam Pwnagotchi! Započinjem ..."
|
||||||
|
|
||||||
|
msgid "New day, new hunt, new pwns!"
|
||||||
|
msgstr "Novi dan, novi lov, novi pnwovi!"
|
||||||
|
|
||||||
|
msgid "Hack the Planet!"
|
||||||
|
msgstr "Hakuj Planetu!"
|
||||||
|
|
||||||
|
msgid "AI ready."
|
||||||
|
msgstr "AI spreman."
|
||||||
|
|
||||||
|
msgid "The neural network is ready."
|
||||||
|
msgstr "Neuronska mreža je spremna."
|
||||||
|
|
||||||
|
msgid "Generating keys, do not turn off ..."
|
||||||
|
msgstr "Generišem ključeve, ne isključuj me..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||||
|
msgstr "Hej, kanal {channel} je slobodan! Tvoj AP će ti se zahvaliti."
|
||||||
|
|
||||||
|
msgid "Reading last session logs ..."
|
||||||
|
msgstr "Čitanje logova poslednje sesije ..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Read {lines_so_far} log lines so far ..."
|
||||||
|
msgstr "Pročitao {lines_so_far} log linija do sada ..."
|
||||||
|
|
||||||
|
msgid "I'm bored ..."
|
||||||
|
msgstr "Dosadno mi je ..."
|
||||||
|
|
||||||
|
msgid "Let's go for a walk!"
|
||||||
|
msgstr "Hajmo u šetnju!"
|
||||||
|
|
||||||
|
msgid "This is the best day of my life!"
|
||||||
|
msgstr "Ovo je najbolji dan mog života!"
|
||||||
|
|
||||||
|
msgid "Shitty day :/"
|
||||||
|
msgstr "Sranje dan :/"
|
||||||
|
|
||||||
|
msgid "I'm extremely bored ..."
|
||||||
|
msgstr "Užasno mi je dosadno ..."
|
||||||
|
|
||||||
|
msgid "I'm very sad ..."
|
||||||
|
msgstr "Jako sam tužan ..."
|
||||||
|
|
||||||
|
msgid "I'm sad"
|
||||||
|
msgstr "Tužan sam"
|
||||||
|
|
||||||
|
msgid "Leave me alone ..."
|
||||||
|
msgstr "Ostavi me na miru ..."
|
||||||
|
|
||||||
|
msgid "I'm mad at you!"
|
||||||
|
msgstr "Ljut sam na tebe!"
|
||||||
|
|
||||||
|
msgid "I'm living the life!"
|
||||||
|
msgstr "Živim ga!"
|
||||||
|
|
||||||
|
msgid "I pwn therefore I am."
|
||||||
|
msgstr "Ja pwnujem dakle postojim."
|
||||||
|
|
||||||
|
msgid "So many networks!!!"
|
||||||
|
msgstr "Tako mnogo mreža!!!"
|
||||||
|
|
||||||
|
msgid "I'm having so much fun!"
|
||||||
|
msgstr "Previše se zabavljam!"
|
||||||
|
|
||||||
|
msgid "My crime is that of curiosity ..."
|
||||||
|
msgstr "Moj zločin je radoznalost ..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Hello {name}! Nice to meet you."
|
||||||
|
msgstr "Zdravo {name}! Drago mi je da te upoznam."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Yo {name}! Sup?"
|
||||||
|
msgstr "Ej {name}! Šta ima?"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Hey {name} how are you doing?"
|
||||||
|
msgstr "Hej {name} kako si?"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Unit {name} is nearby!"
|
||||||
|
msgstr "Jedinica {name} je blizu!"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Uhm ... goodbye {name}"
|
||||||
|
msgstr "Umm ... doviđenja {name}"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{name} is gone ..."
|
||||||
|
msgstr "{name} je nestao ..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Whoops ... {name} is gone."
|
||||||
|
msgstr "Ups ... {name} je nestao."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{name} missed!"
|
||||||
|
msgstr "{name} promašen!"
|
||||||
|
|
||||||
|
msgid "Missed!"
|
||||||
|
msgstr "Promašen!"
|
||||||
|
|
||||||
|
msgid "Good friends are a blessing!"
|
||||||
|
msgstr "Dobri prijatelji su blagoslov!"
|
||||||
|
|
||||||
|
msgid "I love my friends!"
|
||||||
|
msgstr "Volim svoje prijatelje!"
|
||||||
|
|
||||||
|
msgid "Nobody wants to play with me ..."
|
||||||
|
msgstr "Niko ne želi da se igra sa mnom ..."
|
||||||
|
|
||||||
|
msgid "I feel so alone ..."
|
||||||
|
msgstr "Osećam se toliko usamljeno ..."
|
||||||
|
|
||||||
|
msgid "Where's everybody?!"
|
||||||
|
msgstr "Gde su svi?!"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Napping for {secs}s ..."
|
||||||
|
msgstr "Dremam {secs}s ..."
|
||||||
|
|
||||||
|
msgid "Zzzzz"
|
||||||
|
msgstr "Zzzzz"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "ZzzZzzz ({secs}s)"
|
||||||
|
msgstr "ZzzZzzz ({secs}s)"
|
||||||
|
|
||||||
|
msgid "Good night."
|
||||||
|
msgstr "Laku noć."
|
||||||
|
|
||||||
|
msgid "Zzz"
|
||||||
|
msgstr "Zzz"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Waiting for {secs}s ..."
|
||||||
|
msgstr "Čekam {secs}s ..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Looking around ({secs}s)"
|
||||||
|
msgstr "Gledam unaokolo ({secs}s)"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Hey {what} let's be friends!"
|
||||||
|
msgstr "Hej {what} hajde da budemo prijatelji!"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Associating to {what}"
|
||||||
|
msgstr "Povezujem se sa {what}"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Yo {what}!"
|
||||||
|
msgstr "Ej {what}!"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Just decided that {mac} needs no WiFi!"
|
||||||
|
msgstr "Upravo sam odlučio da {mac} ne zahteva WiFi!"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Deauthenticating {mac}"
|
||||||
|
msgstr "Deauthenticating {mac}"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Kickbanning {mac}!"
|
||||||
|
msgstr "Kickbanning {mac}!"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Cool, we got {num} new handshake{plural}!"
|
||||||
|
msgstr "Kul, imamo {num} novih handshakeova"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "You have {count} new message{plural}!"
|
||||||
|
msgstr "Imas {count} novih poruka"
|
||||||
|
|
||||||
|
msgid "Oops, something went wrong ... Rebooting ..."
|
||||||
|
msgstr "Ups, nešto je poslo po zlu ... Restartujem ..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Uploading data to {to} ..."
|
||||||
|
msgstr "Otpremam podatke na {to} ..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Downloading from {name} ..."
|
||||||
|
msgstr "Preuzimam od {name} ..."
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Kicked {num} stations\n"
|
||||||
|
msgstr "Kickovano {num} stanica\n"
|
||||||
|
|
||||||
|
msgid "Made >999 new friends\n"
|
||||||
|
msgstr "Stekao sam >999 novih prijatelja\n"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Made {num} new friends\n"
|
||||||
|
msgstr "Stekao sam {num} novih prijatelja\n"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Got {num} handshakes\n"
|
||||||
|
msgstr "Imam {num} handshakeova\n"
|
||||||
|
|
||||||
|
msgid "Met 1 peer"
|
||||||
|
msgstr "Sreo 1 peera"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Met {num} peers"
|
||||||
|
msgstr "Sreo {num} peerova"
|
||||||
|
|
||||||
|
#, python-brace-format
|
||||||
|
msgid ""
|
||||||
|
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
|
||||||
|
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
|
||||||
|
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
||||||
|
msgstr ""
|
||||||
|
"Pwnujem već {duration} i kickovao sam {deauthed} klijenata! Takođe sam sreo "
|
||||||
|
"{associated} novih prijatelja i pojeo {handshakes} handshakeova! #pwnagotchi "
|
||||||
|
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
||||||
|
|
||||||
|
msgid "hours"
|
||||||
|
msgstr "sati"
|
||||||
|
|
||||||
|
msgid "minutes"
|
||||||
|
msgstr "minuta"
|
||||||
|
|
||||||
|
msgid "seconds"
|
||||||
|
msgstr "sekundi"
|
||||||
|
|
||||||
|
msgid "hour"
|
||||||
|
msgstr "sat"
|
||||||
|
|
||||||
|
msgid "minute"
|
||||||
|
msgstr "minut"
|
||||||
|
|
||||||
|
msgid "second"
|
||||||
|
msgstr "sekunda"
|
Binary file not shown.
@ -9,8 +9,8 @@ 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: 2023-11-16 21:10+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: 2024-03-27 18:40+0800\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: AlanLeung <admin@mcnot.pro>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: Twi\n"
|
"Language: Twi\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -18,218 +18,218 @@ 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 "HI!我是Pwnagotchi!\n程式啟動..."
|
||||||
|
|
||||||
msgid "New day, new hunt, new pwns!"
|
msgid "New day, new hunt, new pwns!"
|
||||||
msgstr ""
|
msgstr "新的一天!\n新的狩獵!新的入侵!"
|
||||||
|
|
||||||
msgid "Hack the Planet!"
|
msgid "Hack the Planet!"
|
||||||
msgstr ""
|
msgstr "我要駭入\n地球的所有人!"
|
||||||
|
|
||||||
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 "產生金鑰中,\n請勿關閉..."
|
||||||
|
|
||||||
#, 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}很順暢!\n你的WIFI會感謝你的。"
|
||||||
|
|
||||||
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 "我的缺點就是\n太好奇了..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hello {name}! Nice to meet you."
|
msgid "Hello {name}! Nice to meet you."
|
||||||
msgstr ""
|
msgstr "尼豪{name}!\n很高興認識你!!!!"
|
||||||
|
|
||||||
#, 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}\n就在附近!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uhm ... goodbye {name}"
|
msgid "Uhm ... goodbye {name}"
|
||||||
msgstr ""
|
msgstr "哦嗚 ... \n拜拜{name}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} is gone ..."
|
msgid "{name} is gone ..."
|
||||||
msgstr ""
|
msgstr "{name}\n不見了 ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Whoops ... {name} is gone."
|
msgid "Whoops ... {name} is gone."
|
||||||
msgstr ""
|
msgstr "哦歐...\n{name}\n不見了。"
|
||||||
|
|
||||||
#, 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 "有個好朋友\n真幸福!"
|
||||||
|
|
||||||
msgid "I love my friends!"
|
msgid "I love my friends!"
|
||||||
msgstr ""
|
msgstr "我喜歡\n我的朋友!"
|
||||||
|
|
||||||
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}秒)"
|
||||||
|
|
||||||
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 "嗨\n{what}\n讓我們來當朋友吧!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Associating to {what}"
|
msgid "Associating to {what}"
|
||||||
msgstr ""
|
msgstr "正在連接\n{what}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Yo {what}!"
|
msgid "Yo {what}!"
|
||||||
msgstr ""
|
msgstr "喲,\n{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 "我要讓\n{mac}\n斷線!\n他不需要上網!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Deauthenticating {mac}"
|
msgid "Deauthenticating {mac}"
|
||||||
msgstr ""
|
msgstr "解除\n{mac}\n的授權中"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Kickbanning {mac}!"
|
msgid "Kickbanning {mac}!"
|
||||||
msgstr ""
|
msgstr "把\n{mac}\n踢出中!"
|
||||||
|
|
||||||
#, 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}個\n新的握手包{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 "哦歐,有些地方出錯了...\n重新啟動中..."
|
||||||
|
|
||||||
#, 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 ""
|
||||||
@ -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 ""
|
||||||
|
"我花了{duration}的時間\n駭入和踢了{deauthed}好多設備."
|
||||||
|
"我還交了好多{associated}新朋友,\n而且抓到了{handshakes}握手包!"
|
||||||
|
"#pwnagotchi#入侵日志 #駭客人生 #入侵整個星球 #天網 #我好棒˙ˇ˙"
|
||||||
|
|
||||||
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 "秒"
|
||||||
|
@ -29,7 +29,6 @@ class FixServices(plugins.Plugin):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.options = dict()
|
self.options = dict()
|
||||||
self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed')
|
|
||||||
self.pattern2 = re.compile(r'wifi error while hopping to channel')
|
self.pattern2 = re.compile(r'wifi error while hopping to channel')
|
||||||
self.pattern3 = re.compile(r'Firmware has halted or crashed')
|
self.pattern3 = re.compile(r'Firmware has halted or crashed')
|
||||||
self.pattern4 = re.compile(r'error 400: could not find interface wlan0mon')
|
self.pattern4 = re.compile(r'error 400: could not find interface wlan0mon')
|
||||||
@ -55,20 +54,6 @@ class FixServices(plugins.Plugin):
|
|||||||
if ",UP," in str(cmd_output):
|
if ",UP," in str(cmd_output):
|
||||||
logging.debug("wlan0mon is up.")
|
logging.debug("wlan0mon is up.")
|
||||||
|
|
||||||
if len(self.pattern.findall(last_lines)) >= 3:
|
|
||||||
if hasattr(agent, 'view'):
|
|
||||||
display = agent.view()
|
|
||||||
display.set('status', 'Blind-Bug detected. Restarting.')
|
|
||||||
display.update(force=True)
|
|
||||||
logging.debug('[Fix_Services] Blind-Bug detected. Restarting.')
|
|
||||||
try:
|
|
||||||
self._tryTurningItOffAndOnAgain(agent)
|
|
||||||
except Exception as err:
|
|
||||||
logging.warning("[Fix_Services turnOffAndOn] %s" % repr(err))
|
|
||||||
|
|
||||||
else:
|
|
||||||
logging.debug("[Fix_Services] Logs look good!")
|
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logging.error("[Fix_Services ip link show wlan0mon]: %s" % repr(err))
|
logging.error("[Fix_Services ip link show wlan0mon]: %s" % repr(err))
|
||||||
try:
|
try:
|
||||||
@ -106,7 +91,7 @@ class FixServices(plugins.Plugin):
|
|||||||
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
|
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
|
||||||
stdout=subprocess.PIPE).stdout))[-10:])
|
stdout=subprocess.PIPE).stdout))[-10:])
|
||||||
other_other_last_lines = ''.join(
|
other_other_last_lines = ''.join(
|
||||||
list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/var/log/pwnagotchi.log'],
|
list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/etc/pwnagotchi/log/pwnagotchi.log'],
|
||||||
stdout=subprocess.PIPE).stdout))[-10:])
|
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")
|
||||||
@ -116,20 +101,8 @@ class FixServices(plugins.Plugin):
|
|||||||
|
|
||||||
logging.debug("[Fix_Services]**** checking")
|
logging.debug("[Fix_Services]**** checking")
|
||||||
|
|
||||||
# Look for pattern 1
|
|
||||||
if len(self.pattern.findall(last_lines)) >= 3:
|
|
||||||
logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
|
|
||||||
if hasattr(agent, 'view'):
|
|
||||||
display.set('status', 'Blind-Bug detected. Restarting.')
|
|
||||||
display.update(force=True)
|
|
||||||
logging.debug('[Fix_Services] Blind-Bug detected. Restarting.')
|
|
||||||
try:
|
|
||||||
self._tryTurningItOffAndOnAgain(agent)
|
|
||||||
except Exception as err:
|
|
||||||
logging.warning("[Fix_Services] TTOAOA: %s" % repr(err))
|
|
||||||
|
|
||||||
# Look for pattern 2
|
# Look for pattern 2
|
||||||
elif len(self.pattern2.findall(other_last_lines)) >= 5:
|
if len(self.pattern2.findall(other_last_lines)) >= 5:
|
||||||
logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
|
logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
|
||||||
if hasattr(agent, 'view'):
|
if hasattr(agent, 'view'):
|
||||||
display.set('status', 'Wifi channel stuck. Restarting recon.')
|
display.set('status', 'Wifi channel stuck. Restarting recon.')
|
||||||
|
@ -14,8 +14,9 @@ class GPIOButtons(plugins.Plugin):
|
|||||||
self.running = False
|
self.running = False
|
||||||
self.ports = {}
|
self.ports = {}
|
||||||
self.commands = None
|
self.commands = None
|
||||||
|
self.options = dict()
|
||||||
|
|
||||||
def runCommand(self, channel):
|
def runcommand(self, channel):
|
||||||
command = self.ports[channel]
|
command = self.ports[channel]
|
||||||
logging.info(f"Button Pressed! Running command: {command}")
|
logging.info(f"Button Pressed! Running command: {command}")
|
||||||
process = subprocess.Popen(command, shell=True, stdin=None, stdout=open("/dev/null", "w"), stderr=None,
|
process = subprocess.Popen(command, shell=True, stdin=None, stdout=open("/dev/null", "w"), stderr=None,
|
||||||
@ -35,8 +36,8 @@ class GPIOButtons(plugins.Plugin):
|
|||||||
gpio = int(gpio)
|
gpio = int(gpio)
|
||||||
self.ports[gpio] = command
|
self.ports[gpio] = command
|
||||||
GPIO.setup(gpio, GPIO.IN, GPIO.PUD_UP)
|
GPIO.setup(gpio, GPIO.IN, GPIO.PUD_UP)
|
||||||
GPIO.add_event_detect(gpio, GPIO.FALLING, callback=self.runCommand, bouncetime=600)
|
GPIO.add_event_detect(gpio, GPIO.FALLING, callback=self.runcommand, bouncetime=600)
|
||||||
#set pimoroni display hat mini LED off/dim
|
# set pimoroni display hat mini LED off/dim
|
||||||
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||||
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||||
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||||
|
@ -47,7 +47,7 @@ class Grid(plugins.Plugin):
|
|||||||
__version__ = '1.0.1'
|
__version__ = '1.0.1'
|
||||||
__license__ = 'GPL3'
|
__license__ = 'GPL3'
|
||||||
__description__ = 'This plugin signals the unit cryptographic identity and list of pwned networks and list of pwned ' \
|
__description__ = 'This plugin signals the unit cryptographic identity and list of pwned networks and list of pwned ' \
|
||||||
'networks to api.pwnagotchi.ai '
|
'networks to opwngrid.xyz '
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.options = dict()
|
self.options = dict()
|
||||||
@ -89,7 +89,7 @@ class Grid(plugins.Plugin):
|
|||||||
logging.debug("checking pcap's")
|
logging.debug("checking pcap's")
|
||||||
config = agent.config()
|
config = agent.config()
|
||||||
|
|
||||||
pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap"))
|
pcap_files = glob.glob(os.path.join(config['bettercap']['handshakes'], "*.pcap"))
|
||||||
num_networks = len(pcap_files)
|
num_networks = len(pcap_files)
|
||||||
reported = self.report.data_field_or('reported', default=[])
|
reported = self.report.data_field_or('reported', default=[])
|
||||||
num_reported = len(reported)
|
num_reported = len(reported)
|
||||||
|
@ -130,7 +130,7 @@ class MemTemp(plugins.Plugin):
|
|||||||
except Exception:
|
except Exception:
|
||||||
# Set default position based on screen type
|
# Set default position based on screen type
|
||||||
if ui.is_waveshare_v2():
|
if ui.is_waveshare_v2():
|
||||||
h_pos = (178, 84)
|
h_pos = (175, 84)
|
||||||
v_pos = (197, 74)
|
v_pos = (197, 74)
|
||||||
elif ui.is_waveshare_v1():
|
elif ui.is_waveshare_v1():
|
||||||
h_pos = (170, 80)
|
h_pos = (170, 80)
|
||||||
|
@ -18,12 +18,14 @@ def systemd_dropin(name, content):
|
|||||||
|
|
||||||
systemctl("daemon-reload")
|
systemctl("daemon-reload")
|
||||||
|
|
||||||
|
|
||||||
def systemctl(command, unit=None):
|
def systemctl(command, unit=None):
|
||||||
if unit:
|
if unit:
|
||||||
os.system("/bin/systemctl %s %s" % (command, unit))
|
os.system("/bin/systemctl %s %s" % (command, unit))
|
||||||
else:
|
else:
|
||||||
os.system("/bin/systemctl %s" % command)
|
os.system("/bin/systemctl %s" % command)
|
||||||
|
|
||||||
|
|
||||||
def run_task(name, options):
|
def run_task(name, options):
|
||||||
task_service_name = "switcher-%s-task.service" % name
|
task_service_name = "switcher-%s-task.service" % name
|
||||||
# save all the commands to a shell script
|
# save all the commands to a shell script
|
||||||
@ -57,7 +59,7 @@ def run_task(name, options):
|
|||||||
""" % (name, task_service_name, name))
|
""" % (name, task_service_name, name))
|
||||||
|
|
||||||
if 'reboot' in options and options['reboot']:
|
if 'reboot' in options and options['reboot']:
|
||||||
# create a indication file!
|
# create an indication file!
|
||||||
# if this file is set, we want the switcher-tasks to run
|
# if this file is set, we want the switcher-tasks to run
|
||||||
open('/root/.switcher', 'a').close()
|
open('/root/.switcher', 'a').close()
|
||||||
|
|
||||||
@ -98,6 +100,7 @@ def run_task(name, options):
|
|||||||
systemctl("daemon-reload")
|
systemctl("daemon-reload")
|
||||||
systemctl("start", task_service_name)
|
systemctl("start", task_service_name)
|
||||||
|
|
||||||
|
|
||||||
class Switcher(plugins.Plugin):
|
class Switcher(plugins.Plugin):
|
||||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||||
__version__ = '0.0.1'
|
__version__ = '0.0.1'
|
||||||
|
@ -10,13 +10,17 @@ class Widget(object):
|
|||||||
def draw(self, canvas, drawer):
|
def draw(self, canvas, drawer):
|
||||||
raise Exception("not implemented")
|
raise Exception("not implemented")
|
||||||
|
|
||||||
|
# canvas.paste: https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.paste
|
||||||
|
# takes mask variable, to identify color system. (not used for pwnagotchi yet)
|
||||||
|
# Pwn should use "1" since its mainly black or white displays.
|
||||||
class Bitmap(Widget):
|
class Bitmap(Widget):
|
||||||
def __init__(self, path, xy, color=0):
|
def __init__(self, path, xy, color=0):
|
||||||
super().__init__(xy, color)
|
super().__init__(xy, color)
|
||||||
self.image = Image.open(path)
|
self.image = Image.open(path)
|
||||||
|
|
||||||
def draw(self, canvas, drawer):
|
def draw(self, canvas, drawer):
|
||||||
|
if self.color == 0xFF:
|
||||||
|
self.image = ImageOps.invert(self.image)
|
||||||
canvas.paste(self.image, self.xy)
|
canvas.paste(self.image, self.xy)
|
||||||
|
|
||||||
|
|
||||||
|
@ -264,6 +264,12 @@ class Display(View):
|
|||||||
|
|
||||||
def is_waveshareoledlcd(self):
|
def is_waveshareoledlcd(self):
|
||||||
return self._implementation.name == 'waveshareoledlcd'
|
return self._implementation.name == 'waveshareoledlcd'
|
||||||
|
|
||||||
|
def is_waveshareoledlcdvert(self):
|
||||||
|
return self._implementation.name == 'waveshareoledlcdvert'
|
||||||
|
|
||||||
|
def is_i2coled(self):
|
||||||
|
return self._implementation.name == 'i2coled'
|
||||||
|
|
||||||
def is_waveshare35lcd(self):
|
def is_waveshare35lcd(self):
|
||||||
return self._implementation.name == 'waveshare35lcd'
|
return self._implementation.name == 'waveshare35lcd'
|
||||||
|
@ -104,6 +104,14 @@ def display_for(config):
|
|||||||
from pwnagotchi.ui.hw.waveshareoledlcd import Waveshareoledlcd
|
from pwnagotchi.ui.hw.waveshareoledlcd import Waveshareoledlcd
|
||||||
return Waveshareoledlcd(config)
|
return Waveshareoledlcd(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshareoledlcdvert':
|
||||||
|
from pwnagotchi.ui.hw.waveshareoledlcdvert import Waveshareoledlcdvert
|
||||||
|
return Waveshareoledlcdvert(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'i2coled':
|
||||||
|
from pwnagotchi.ui.hw.i2coled import I2COled
|
||||||
|
return I2COled(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare1in02':
|
elif config['ui']['display']['type'] == 'waveshare1in02':
|
||||||
from pwnagotchi.ui.hw.waveshare1in02 import Waveshare1in02
|
from pwnagotchi.ui.hw.waveshare1in02 import Waveshare1in02
|
||||||
return Waveshare1in02(config)
|
return Waveshare1in02(config)
|
||||||
|
@ -34,10 +34,10 @@ class DisplayHatMini(DisplayImpl):
|
|||||||
def initialize(self):
|
def initialize(self):
|
||||||
logging.info("initializing Display Hat Mini")
|
logging.info("initializing Display Hat Mini")
|
||||||
from pwnagotchi.ui.hw.libs.pimoroni.displayhatmini.ST7789 import ST7789
|
from pwnagotchi.ui.hw.libs.pimoroni.displayhatmini.ST7789 import ST7789
|
||||||
self._display = ST7789(0, 1, 9, 13)
|
self._display = ST7789(0, 1, 9, 13, width=self._layout['width'], height=self._layout['height'], rotation=0)
|
||||||
|
|
||||||
def render(self, canvas):
|
def render(self, canvas):
|
||||||
self._display.display(canvas)
|
self._display.display(canvas)
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self._display.clear()
|
pass
|
||||||
|
67
pwnagotchi/ui/hw/i2coled.py
Normal file
67
pwnagotchi/ui/hw/i2coled.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# Created for the Pwnagotchi project by RasTacsko
|
||||||
|
# HW libraries are based on the adafruit python SSD1306 repo:
|
||||||
|
# https://github.com/adafruit/Adafruit_Python_SSD1306
|
||||||
|
# SMBus parts coming from BLavery's lib_oled96 repo:
|
||||||
|
# https://github.com/BLavery/lib_oled96
|
||||||
|
# I2C address, width and height import from config.toml made by NurseJackass
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import pwnagotchi.ui.fonts as fonts
|
||||||
|
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||||
|
|
||||||
|
#
|
||||||
|
# Default is 128x64 display on i2c address 0x3C
|
||||||
|
#
|
||||||
|
# Configure i2c address and dimensions in config.toml:
|
||||||
|
#
|
||||||
|
# ui.display.type = "i2coled"
|
||||||
|
# ui.display.i2c_addr = 0x3C
|
||||||
|
# ui.display.width = 128
|
||||||
|
# ui.display.height = 64
|
||||||
|
#
|
||||||
|
|
||||||
|
class I2COled(DisplayImpl):
|
||||||
|
def __init__(self, config):
|
||||||
|
self._config = config['ui']['display']
|
||||||
|
super(I2COled, self).__init__(config, 'i2coled')
|
||||||
|
|
||||||
|
def layout(self):
|
||||||
|
fonts.setup(8, 8, 8, 10, 10, 8)
|
||||||
|
self._layout['width'] = self._config['width'] if 'width' in self._config else 128
|
||||||
|
self._layout['height'] = self._config['height'] if 'height' in self._config else 64
|
||||||
|
self._layout['face'] = (0, 30)
|
||||||
|
self._layout['name'] = (0, 10)
|
||||||
|
self._layout['channel'] = (72, 10)
|
||||||
|
self._layout['aps'] = (0, 0)
|
||||||
|
self._layout['uptime'] = (87, 0)
|
||||||
|
self._layout['line1'] = [0, 9, 128, 9]
|
||||||
|
self._layout['line2'] = [0, 54, 128, 54]
|
||||||
|
self._layout['friend_face'] = (0, 41)
|
||||||
|
self._layout['friend_name'] = (40, 43)
|
||||||
|
self._layout['shakes'] = (0, 55)
|
||||||
|
self._layout['mode'] = (107, 10)
|
||||||
|
self._layout['status'] = {
|
||||||
|
'pos': (37, 19),
|
||||||
|
'font': fonts.status_font(fonts.Small),
|
||||||
|
'max': 18
|
||||||
|
}
|
||||||
|
return self._layout
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
i2caddr = self._config['i2c_addr'] if 'i2c_addr' in self._config else 0x3C
|
||||||
|
width = self._config['width'] if 'width' in self._config else 128
|
||||||
|
height = self._config['height'] if 'height' in self._config else 64
|
||||||
|
|
||||||
|
logging.info("initializing %dx%d I2C Oled Display on address 0x%X" % (width, height, i2caddr))
|
||||||
|
|
||||||
|
from pwnagotchi.ui.hw.libs.i2coled.epd import EPD
|
||||||
|
self._display = EPD(address=i2caddr, width=width, height=height)
|
||||||
|
self._display.Init()
|
||||||
|
self._display.Clear()
|
||||||
|
|
||||||
|
def render(self, canvas):
|
||||||
|
self._display.display(canvas)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self._display.clear()
|
312
pwnagotchi/ui/hw/libs/i2coled/SSD1306.py
Normal file
312
pwnagotchi/ui/hw/libs/i2coled/SSD1306.py
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
# Copyright (c) 2014 Adafruit Industries
|
||||||
|
# Author: Tony DiCola
|
||||||
|
#
|
||||||
|
# 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 FOR 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.
|
||||||
|
#
|
||||||
|
# SMBus parts coming from BLavery's lib_oled96 repo:
|
||||||
|
# https://github.com/BLavery/lib_oled96
|
||||||
|
#
|
||||||
|
# Modified for the Pwnagotchi project by RasTacsko
|
||||||
|
# Using SMBus, spidev RPi.GPIO for I2C communication instead of Adafruit libraries
|
||||||
|
# spidev maybe not necessary... needs some checking!!!
|
||||||
|
# ToDo:
|
||||||
|
# rotation support for vertical layouts
|
||||||
|
# checking luma oled library for support other chipsets/resolutions
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
# import spidev
|
||||||
|
from smbus import SMBus
|
||||||
|
i2cbus = SMBus(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
SSD1306_I2C_ADDRESS = 0x3C # 011110+SA0+RW - 0x3C or 0x3D
|
||||||
|
SSD1306_SETCONTRAST = 0x81
|
||||||
|
SSD1306_DISPLAYALLON_RESUME = 0xA4
|
||||||
|
SSD1306_DISPLAYALLON = 0xA5
|
||||||
|
SSD1306_NORMALDISPLAY = 0xA6
|
||||||
|
SSD1306_INVERTDISPLAY = 0xA7
|
||||||
|
SSD1306_DISPLAYOFF = 0xAE
|
||||||
|
SSD1306_DISPLAYON = 0xAF
|
||||||
|
SSD1306_SETDISPLAYOFFSET = 0xD3
|
||||||
|
SSD1306_SETCOMPINS = 0xDA
|
||||||
|
SSD1306_SETVCOMDETECT = 0xDB
|
||||||
|
SSD1306_SETDISPLAYCLOCKDIV = 0xD5
|
||||||
|
SSD1306_SETPRECHARGE = 0xD9
|
||||||
|
SSD1306_SETMULTIPLEX = 0xA8
|
||||||
|
SSD1306_SETLOWCOLUMN = 0x00
|
||||||
|
SSD1306_SETHIGHCOLUMN = 0x10
|
||||||
|
SSD1306_SETSTARTLINE = 0x40
|
||||||
|
SSD1306_MEMORYMODE = 0x20
|
||||||
|
SSD1306_COLUMNADDR = 0x21
|
||||||
|
SSD1306_PAGEADDR = 0x22
|
||||||
|
SSD1306_COMSCANINC = 0xC0
|
||||||
|
SSD1306_COMSCANDEC = 0xC8
|
||||||
|
SSD1306_SEGREMAP = 0xA0
|
||||||
|
SSD1306_CHARGEPUMP = 0x8D
|
||||||
|
SSD1306_EXTERNALVCC = 0x1
|
||||||
|
SSD1306_SWITCHCAPVCC = 0x2
|
||||||
|
|
||||||
|
# Scrolling constants
|
||||||
|
SSD1306_ACTIVATE_SCROLL = 0x2F
|
||||||
|
SSD1306_DEACTIVATE_SCROLL = 0x2E
|
||||||
|
SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3
|
||||||
|
SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26
|
||||||
|
SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27
|
||||||
|
SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29
|
||||||
|
SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A
|
||||||
|
|
||||||
|
|
||||||
|
class SSD1306Base(object):
|
||||||
|
"""Base class for SSD1306-based OLED displays. Implementors should subclass
|
||||||
|
and provide an implementation for the _initialize function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, width, height, address=SSD1306_I2C_ADDRESS, bus=None):
|
||||||
|
self._log = logging.getLogger('Adafruit_SSD1306.SSD1306Base')
|
||||||
|
self.cmd_mode = 0x00
|
||||||
|
self.data_mode = 0x40
|
||||||
|
self.bus = i2cbus
|
||||||
|
self.addr = address
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self._pages = height//8
|
||||||
|
self._buffer = [0]*(width*self._pages)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def command(self, *cmd):
|
||||||
|
"""Send command byte to display."""
|
||||||
|
# I2C write.
|
||||||
|
assert(len(cmd) <= 31)
|
||||||
|
try:
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
|
def data(self, data):
|
||||||
|
"""Send byte of data to display."""
|
||||||
|
# I2C write.
|
||||||
|
try:
|
||||||
|
for i in range(0, len(data), 31):
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31]))
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
|
def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
|
||||||
|
"""Initialize display."""
|
||||||
|
# Save vcc state.
|
||||||
|
self._vccstate = vccstate
|
||||||
|
# Reset and initialize display.
|
||||||
|
self._initialize()
|
||||||
|
# Turn on the display.
|
||||||
|
self.command(SSD1306_DISPLAYON)
|
||||||
|
|
||||||
|
def ShowImage(self):
|
||||||
|
"""
|
||||||
|
The image on the "canvas" is flushed through to the hardware display.
|
||||||
|
Takes the 1-bit image and dumps it to the SSD1306 OLED display.
|
||||||
|
"""
|
||||||
|
self.command(SSD1306_COLUMNADDR)
|
||||||
|
self.command(0) # Column start address. (0 = reset)
|
||||||
|
self.command(self.width-1) # Column end address.
|
||||||
|
self.command(SSD1306_PAGEADDR)
|
||||||
|
self.command(0) # Page start address. (0 = reset)
|
||||||
|
self.command(self._pages-1) # Page end address.
|
||||||
|
try:
|
||||||
|
for i in range(0, len(self._buffer), 16):
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
"""Set buffer to value of Python Imaging Library image. The image should
|
||||||
|
be in 1 bit mode and a size equal to the display size.
|
||||||
|
"""
|
||||||
|
if image.mode != '1':
|
||||||
|
raise ValueError('Image must be in mode 1.')
|
||||||
|
imwidth, imheight = image.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))
|
||||||
|
# Grab all the pixels from the image, faster than getpixel.
|
||||||
|
pix = image.load()
|
||||||
|
# Iterate through the memory pages
|
||||||
|
index = 0
|
||||||
|
for page in range(self._pages):
|
||||||
|
# Iterate through all x axis columns.
|
||||||
|
for x in range(self.width):
|
||||||
|
# Set the bits for the column of pixels at the current position.
|
||||||
|
bits = 0
|
||||||
|
# Don't use range here as it's a bit slow
|
||||||
|
for bit in [0, 1, 2, 3, 4, 5, 6, 7]:
|
||||||
|
bits = bits << 1
|
||||||
|
bits |= 0 if pix[(x, page*8+7-bit)] == 0 else 1
|
||||||
|
# Update buffer byte and increment to next byte.
|
||||||
|
self._buffer[index] = bits
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Clear contents of image buffer."""
|
||||||
|
self._buffer = [0]*(self.width*self._pages)
|
||||||
|
|
||||||
|
def set_contrast(self, contrast):
|
||||||
|
"""Sets the contrast of the display. Contrast should be a value between
|
||||||
|
0 and 255."""
|
||||||
|
if contrast < 0 or contrast > 255:
|
||||||
|
raise ValueError('Contrast must be a value from 0 to 255 (inclusive).')
|
||||||
|
self.command(SSD1306_SETCONTRAST)
|
||||||
|
self.command(contrast)
|
||||||
|
|
||||||
|
def dim(self, dim):
|
||||||
|
"""Adjusts contrast to dim the display if dim is True, otherwise sets the
|
||||||
|
contrast to normal brightness if dim is False.
|
||||||
|
"""
|
||||||
|
# Assume dim display.
|
||||||
|
contrast = 0
|
||||||
|
# Adjust contrast based on VCC if not dimming.
|
||||||
|
if not dim:
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
contrast = 0x9F
|
||||||
|
else:
|
||||||
|
contrast = 0xCF
|
||||||
|
self.set_contrast(contrast)
|
||||||
|
|
||||||
|
class SSD1306_128_64(SSD1306Base):
|
||||||
|
def __init__(self, width, height, address=None, bus=None):
|
||||||
|
# Call base class constructor.
|
||||||
|
super(SSD1306_128_64, self).__init__(128, 64, address, bus)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
# 128x64 pixel specific initialization.
|
||||||
|
self.command(SSD1306_DISPLAYOFF) # 0xAE
|
||||||
|
self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5
|
||||||
|
self.command(0x80) # the suggested ratio 0x80
|
||||||
|
self.command(SSD1306_SETMULTIPLEX) # 0xA8
|
||||||
|
self.command(0x3F)
|
||||||
|
self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3
|
||||||
|
self.command(0x0) # no offset
|
||||||
|
self.command(SSD1306_SETSTARTLINE | 0x0) # line #0
|
||||||
|
self.command(SSD1306_CHARGEPUMP) # 0x8D
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x10)
|
||||||
|
else:
|
||||||
|
self.command(0x14)
|
||||||
|
self.command(SSD1306_MEMORYMODE) # 0x20
|
||||||
|
self.command(0x00) # 0x0 act like ks0108
|
||||||
|
self.command(SSD1306_SEGREMAP | 0x1)
|
||||||
|
self.command(SSD1306_COMSCANDEC)
|
||||||
|
self.command(SSD1306_SETCOMPINS) # 0xDA
|
||||||
|
self.command(0x12)
|
||||||
|
self.command(SSD1306_SETCONTRAST) # 0x81
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x9F)
|
||||||
|
else:
|
||||||
|
self.command(0xCF)
|
||||||
|
self.command(SSD1306_SETPRECHARGE) # 0xd9
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x22)
|
||||||
|
else:
|
||||||
|
self.command(0xF1)
|
||||||
|
self.command(SSD1306_SETVCOMDETECT) # 0xDB
|
||||||
|
self.command(0x40)
|
||||||
|
self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4
|
||||||
|
self.command(SSD1306_NORMALDISPLAY) # 0xA6
|
||||||
|
|
||||||
|
class SSD1306_128_32(SSD1306Base):
|
||||||
|
def __init__(self, width, height, address=None, bus=None):
|
||||||
|
# Call base class constructor.
|
||||||
|
super(SSD1306_128_32, self).__init__(128, 32, address, bus)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
# 128x32 pixel specific initialization.
|
||||||
|
self.command(SSD1306_DISPLAYOFF) # 0xAE
|
||||||
|
self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5
|
||||||
|
self.command(0x80) # the suggested ratio 0x80
|
||||||
|
self.command(SSD1306_SETMULTIPLEX) # 0xA8
|
||||||
|
self.command(0x1F)
|
||||||
|
self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3
|
||||||
|
self.command(0x0) # no offset
|
||||||
|
self.command(SSD1306_SETSTARTLINE | 0x0) # line #0
|
||||||
|
self.command(SSD1306_CHARGEPUMP) # 0x8D
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x10)
|
||||||
|
else:
|
||||||
|
self.command(0x14)
|
||||||
|
self.command(SSD1306_MEMORYMODE) # 0x20
|
||||||
|
self.command(0x00) # 0x0 act like ks0108
|
||||||
|
self.command(SSD1306_SEGREMAP | 0x1)
|
||||||
|
self.command(SSD1306_COMSCANDEC)
|
||||||
|
self.command(SSD1306_SETCOMPINS) # 0xDA
|
||||||
|
self.command(0x02)
|
||||||
|
self.command(SSD1306_SETCONTRAST) # 0x81
|
||||||
|
self.command(0x8F)
|
||||||
|
self.command(SSD1306_SETPRECHARGE) # 0xd9
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x22)
|
||||||
|
else:
|
||||||
|
self.command(0xF1)
|
||||||
|
self.command(SSD1306_SETVCOMDETECT) # 0xDB
|
||||||
|
self.command(0x40)
|
||||||
|
self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4
|
||||||
|
self.command(SSD1306_NORMALDISPLAY) # 0xA6
|
||||||
|
|
||||||
|
|
||||||
|
class SSD1306_96_16(SSD1306Base):
|
||||||
|
def __init__(self, width, height, address=None, bus=None):
|
||||||
|
# Call base class constructor.
|
||||||
|
super(SSD1306_96_16, self).__init__(96, 16, address, bus)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
# 128x32 pixel specific initialization.
|
||||||
|
self.command(SSD1306_DISPLAYOFF) # 0xAE
|
||||||
|
self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5
|
||||||
|
self.command(0x60) # the suggested ratio 0x60
|
||||||
|
self.command(SSD1306_SETMULTIPLEX) # 0xA8
|
||||||
|
self.command(0x0F)
|
||||||
|
self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3
|
||||||
|
self.command(0x0) # no offset
|
||||||
|
self.command(SSD1306_SETSTARTLINE | 0x0) # line #0
|
||||||
|
self.command(SSD1306_CHARGEPUMP) # 0x8D
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x10)
|
||||||
|
else:
|
||||||
|
self.command(0x14)
|
||||||
|
self.command(SSD1306_MEMORYMODE) # 0x20
|
||||||
|
self.command(0x00) # 0x0 act like ks0108
|
||||||
|
self.command(SSD1306_SEGREMAP | 0x1)
|
||||||
|
self.command(SSD1306_COMSCANDEC)
|
||||||
|
self.command(SSD1306_SETCOMPINS) # 0xDA
|
||||||
|
self.command(0x02)
|
||||||
|
self.command(SSD1306_SETCONTRAST) # 0x81
|
||||||
|
self.command(0x8F)
|
||||||
|
self.command(SSD1306_SETPRECHARGE) # 0xd9
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x22)
|
||||||
|
else:
|
||||||
|
self.command(0xF1)
|
||||||
|
self.command(SSD1306_SETVCOMDETECT) # 0xDB
|
||||||
|
self.command(0x40)
|
||||||
|
self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4
|
||||||
|
self.command(SSD1306_NORMALDISPLAY) # 0xA6
|
34
pwnagotchi/ui/hw/libs/i2coled/epd.py
Normal file
34
pwnagotchi/ui/hw/libs/i2coled/epd.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from . import SSD1306
|
||||||
|
|
||||||
|
# Display resolution, change if the screen resolution is changed!
|
||||||
|
EPD_WIDTH = 128
|
||||||
|
EPD_HEIGHT = 64
|
||||||
|
|
||||||
|
# Available screen resolutions:
|
||||||
|
# disp = SSD1306.SSD1306_128_32(128, 32, address=0x3C)
|
||||||
|
# disp = SSD1306.SSD1306_96_16(96, 16, address=0x3C)
|
||||||
|
# If you change for different resolution, you have to modify the layout in pwnagotchi/ui/hw/i2coled.py
|
||||||
|
|
||||||
|
class EPD(object):
|
||||||
|
|
||||||
|
def __init__(self, address=0x3D, width=EPD_WIDTH, height=EPD_HEIGHT):
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
|
||||||
|
# choose subclass based on dimensions
|
||||||
|
if height == 32:
|
||||||
|
self.disp = SSD1306.SSD1306_128_32(width, height, address)
|
||||||
|
elif height == 16:
|
||||||
|
self.disp = SSD1306.SSD1306_96_16(width, height, address)
|
||||||
|
else:
|
||||||
|
self.disp = SSD1306.SSD1306_128_64(width, height, address)
|
||||||
|
|
||||||
|
def Init(self):
|
||||||
|
self.disp.begin()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.disp.clear()
|
||||||
|
|
||||||
|
def display(self, image):
|
||||||
|
self.disp.getbuffer(image)
|
||||||
|
self.disp.ShowImage()
|
@ -33,6 +33,8 @@ import sys
|
|||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -43,6 +45,8 @@ class RaspberryPi:
|
|||||||
CS_PIN = 8
|
CS_PIN = 8
|
||||||
BUSY_PIN = 24
|
BUSY_PIN = 24
|
||||||
PWR_PIN = 18
|
PWR_PIN = 18
|
||||||
|
MOSI_PIN = 10
|
||||||
|
SCLK_PIN = 11
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
import spidev
|
import spidev
|
||||||
@ -98,13 +102,45 @@ class RaspberryPi:
|
|||||||
def spi_writebyte2(self, data):
|
def spi_writebyte2(self, data):
|
||||||
self.SPI.writebytes2(data)
|
self.SPI.writebytes2(data)
|
||||||
|
|
||||||
def module_init(self):
|
def DEV_SPI_write(self, data):
|
||||||
|
self.DEV_SPI.DEV_SPI_SendData(data)
|
||||||
|
|
||||||
|
def DEV_SPI_nwrite(self, data):
|
||||||
|
self.DEV_SPI.DEV_SPI_SendnData(data)
|
||||||
|
|
||||||
|
def DEV_SPI_read(self):
|
||||||
|
return self.DEV_SPI.DEV_SPI_ReadData()
|
||||||
|
|
||||||
|
def module_init(self, cleanup=False):
|
||||||
self.GPIO_PWR_PIN.on()
|
self.GPIO_PWR_PIN.on()
|
||||||
|
|
||||||
# SPI device, bus = 0, device = 0
|
if cleanup:
|
||||||
self.SPI.open(0, 0)
|
find_dirs = [
|
||||||
self.SPI.max_speed_hz = 4000000
|
os.path.dirname(os.path.realpath(__file__)),
|
||||||
self.SPI.mode = 0b00
|
'/usr/local/lib',
|
||||||
|
'/usr/lib',
|
||||||
|
]
|
||||||
|
self.DEV_SPI = None
|
||||||
|
for find_dir in find_dirs:
|
||||||
|
val = int(os.popen('getconf LONG_BIT').read())
|
||||||
|
logging.debug("System is %d bit" % val)
|
||||||
|
if val == 64:
|
||||||
|
so_filename = os.path.join(find_dir, 'DEV_Config_64.so')
|
||||||
|
else:
|
||||||
|
so_filename = os.path.join(find_dir, 'DEV_Config_32.so')
|
||||||
|
if os.path.exists(so_filename):
|
||||||
|
self.DEV_SPI = CDLL(so_filename)
|
||||||
|
break
|
||||||
|
if self.DEV_SPI is None:
|
||||||
|
RuntimeError('Cannot find DEV_Config.so')
|
||||||
|
|
||||||
|
self.DEV_SPI.DEV_Module_Init()
|
||||||
|
|
||||||
|
else:
|
||||||
|
# SPI device, bus = 0, device = 0
|
||||||
|
self.SPI.open(0, 0)
|
||||||
|
self.SPI.max_speed_hz = 4000000
|
||||||
|
self.SPI.mode = 0b00
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def module_exit(self, cleanup=False):
|
def module_exit(self, cleanup=False):
|
||||||
@ -127,6 +163,4 @@ class RaspberryPi:
|
|||||||
implementation = RaspberryPi()
|
implementation = RaspberryPi()
|
||||||
|
|
||||||
for func in [x for x in dir(implementation) if not x.startswith('_')]:
|
for func in [x for x in dir(implementation) if not x.startswith('_')]:
|
||||||
setattr(sys.modules[__name__], func, getattr(implementation, func))
|
setattr(sys.modules[__name__], func, getattr(implementation, func))
|
||||||
|
|
||||||
### END OF FILE ###
|
|
@ -446,7 +446,7 @@ class EPD:
|
|||||||
|
|
||||||
def display_4Gray(self, image):
|
def display_4Gray(self, image):
|
||||||
self.send_command(0x24)
|
self.send_command(0x24)
|
||||||
for i in range(0, 48000): # 5808*4 46464
|
for i in range(0, 5808): # 5808*4 46464
|
||||||
temp3 = 0
|
temp3 = 0
|
||||||
for j in range(0, 2):
|
for j in range(0, 2):
|
||||||
temp1 = image[i * 2 + j]
|
temp1 = image[i * 2 + j]
|
||||||
@ -478,7 +478,7 @@ class EPD:
|
|||||||
self.send_data(temp3)
|
self.send_data(temp3)
|
||||||
|
|
||||||
self.send_command(0x26)
|
self.send_command(0x26)
|
||||||
for i in range(0, 48000): # 5808*4 46464
|
for i in range(0, 5808): # 5808*4 46464
|
||||||
temp3 = 0
|
temp3 = 0
|
||||||
for j in range(0, 2):
|
for j in range(0, 2):
|
||||||
temp1 = image[i * 2 + j]
|
temp1 = image[i * 2 + j]
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from pwnagotchi.ui.hw.libs.waveshare.epaper import epdconfig
|
from .. import epdconfig
|
||||||
|
|
||||||
# Display resolution
|
# Display resolution
|
||||||
EPD_WIDTH = 400
|
EPD_WIDTH = 400
|
||||||
@ -45,6 +45,10 @@ 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.flag = 0
|
||||||
|
|
||||||
|
if (epdconfig.module_init(cleanup=True) != 0):
|
||||||
|
return -1
|
||||||
|
|
||||||
# Hardware reset
|
# Hardware reset
|
||||||
def reset(self):
|
def reset(self):
|
||||||
@ -58,13 +62,13 @@ class EPD:
|
|||||||
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.DEV_SPI_write(command)
|
||||||
epdconfig.digital_write(self.cs_pin, 1)
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
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)
|
||||||
epdconfig.spi_writebyte([data])
|
epdconfig.DEV_SPI_write(data)
|
||||||
epdconfig.digital_write(self.cs_pin, 1)
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
# send a lot of data
|
# send a lot of data
|
||||||
@ -76,23 +80,77 @@ class EPD:
|
|||||||
|
|
||||||
def ReadBusy(self):
|
def ReadBusy(self):
|
||||||
logger.debug("e-Paper busy")
|
logger.debug("e-Paper busy")
|
||||||
self.send_command(0x71)
|
if (self.flag == 1):
|
||||||
while (epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
while (epdconfig.digital_read(self.busy_pin) == 1):
|
||||||
self.send_command(0x71)
|
epdconfig.delay_ms(100)
|
||||||
epdconfig.delay_ms(20)
|
|
||||||
|
else:
|
||||||
|
while (epdconfig.digital_read(self.busy_pin) == 0):
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
logger.debug("e-Paper busy release")
|
logger.debug("e-Paper busy release")
|
||||||
|
|
||||||
|
def TurnOnDisplay(self):
|
||||||
|
if (self.flag == 1):
|
||||||
|
self.send_command(0x22)
|
||||||
|
self.send_data(0xF7)
|
||||||
|
self.send_command(0x20)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
if (epdconfig.module_init() != 0):
|
i = 0x00
|
||||||
return -1
|
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
self.send_command(0x2F)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
i = epdconfig.DEV_SPI_read()
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
# print(i)
|
||||||
|
|
||||||
self.send_command(0x04);
|
if (i == 0x01):
|
||||||
self.ReadBusy();
|
self.flag = 1
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x12)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
self.send_command(0x00);
|
self.send_command(0x3C)
|
||||||
self.send_data(0x0f);
|
self.send_data(0x05)
|
||||||
|
|
||||||
|
self.send_command(0x18)
|
||||||
|
self.send_data(0x80)
|
||||||
|
|
||||||
|
self.send_command(0x11)
|
||||||
|
self.send_data(0x03)
|
||||||
|
|
||||||
|
self.send_command(0x44)
|
||||||
|
self.send_data(0x00)
|
||||||
|
self.send_data(self.width // 8 - 1)
|
||||||
|
|
||||||
|
self.send_command(0x45)
|
||||||
|
self.send_data(0x00)
|
||||||
|
self.send_data(0x00)
|
||||||
|
self.send_data((self.height - 1) % 256)
|
||||||
|
self.send_data((self.height - 1) // 256)
|
||||||
|
|
||||||
|
self.send_command(0x4E)
|
||||||
|
self.send_data(0x00)
|
||||||
|
self.send_command(0x4F)
|
||||||
|
self.send_data(0x00)
|
||||||
|
self.send_data(0x00)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.flag = 0
|
||||||
|
self.send_command(0x04) # POWER_ON
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x00) # panel setting
|
||||||
|
self.send_data(0x0f)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -121,40 +179,79 @@ class EPD:
|
|||||||
return buf
|
return buf
|
||||||
|
|
||||||
def display(self, imageblack, imagered):
|
def display(self, imageblack, imagered):
|
||||||
self.send_command(0x10)
|
high = self.height
|
||||||
self.send_data2(imageblack)
|
if (self.width % 8 == 0):
|
||||||
|
wide = self.width // 8
|
||||||
|
else:
|
||||||
|
wide = self.width // 8 + 1
|
||||||
|
|
||||||
self.send_command(0x13)
|
if (self.flag == 1):
|
||||||
self.send_data2(imagered)
|
self.send_command(0x24)
|
||||||
|
for j in range(0, high):
|
||||||
|
for i in range(0, wide):
|
||||||
|
self.send_data(imageblack[i + j * wide])
|
||||||
|
|
||||||
self.send_command(0x12)
|
self.send_command(0x26)
|
||||||
epdconfig.delay_ms(20)
|
for j in range(0, high):
|
||||||
self.ReadBusy()
|
for i in range(0, wide):
|
||||||
|
self.send_data(~imagered[i + j * wide])
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.send_command(0x10)
|
||||||
|
for j in range(0, high):
|
||||||
|
for i in range(0, wide):
|
||||||
|
self.send_data(imageblack[i + j * wide])
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for j in range(0, high):
|
||||||
|
for i in range(0, wide):
|
||||||
|
self.send_data(imagered[i + j * wide])
|
||||||
|
|
||||||
|
self.TurnOnDisplay()
|
||||||
|
|
||||||
def Clear(self):
|
def Clear(self):
|
||||||
if self.width % 8 == 0:
|
high = self.height
|
||||||
linewidth = int(self.width / 8)
|
if (self.width % 8 == 0):
|
||||||
|
wide = self.width // 8
|
||||||
else:
|
else:
|
||||||
linewidth = int(self.width / 8) + 1
|
wide = self.width // 8 + 1
|
||||||
|
|
||||||
self.send_command(0x10)
|
if (self.flag == 1):
|
||||||
self.send_data2([0xff] * int(self.height * linewidth))
|
self.send_command(0x24)
|
||||||
|
for j in range(0, high):
|
||||||
|
for i in range(0, wide):
|
||||||
|
self.send_data(0xff)
|
||||||
|
|
||||||
self.send_command(0x13)
|
self.send_command(0x26)
|
||||||
self.send_data2([0xff] * int(self.height * linewidth))
|
for j in range(0, high):
|
||||||
|
for i in range(0, wide):
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
self.send_command(0x12)
|
else:
|
||||||
epdconfig.delay_ms(20)
|
self.send_command(0x10)
|
||||||
self.ReadBusy()
|
for j in range(0, high):
|
||||||
|
for i in range(0, wide):
|
||||||
|
self.send_data(0xff)
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for j in range(0, high):
|
||||||
|
for i in range(0, wide):
|
||||||
|
self.send_data(0xff)
|
||||||
|
|
||||||
|
self.TurnOnDisplay()
|
||||||
|
|
||||||
def sleep(self):
|
def sleep(self):
|
||||||
self.send_command(0X50)
|
if (self.flag == 1):
|
||||||
self.send_data(0xf7) # border floating
|
self.send_command(0X10)
|
||||||
|
self.send_data(0x03)
|
||||||
|
|
||||||
self.send_command(0X02) # power off
|
else:
|
||||||
self.ReadBusy() # waiting for the electronic paper IC to release the idle signal
|
self.send_command(0X50)
|
||||||
self.send_command(0X07) # deep sleep
|
self.send_data(0xf7)
|
||||||
self.send_data(0xA5)
|
self.send_command(0X02)
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0X07)
|
||||||
|
self.send_data(0xA5)
|
||||||
|
|
||||||
epdconfig.delay_ms(2000)
|
epdconfig.delay_ms(2000)
|
||||||
epdconfig.module_exit()
|
epdconfig.module_exit()
|
||||||
|
294
pwnagotchi/ui/hw/libs/waveshare/oled/oledlcd/SSD1306.py
Normal file
294
pwnagotchi/ui/hw/libs/waveshare/oled/oledlcd/SSD1306.py
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
# Copyright (c) 2014 Adafruit Industries
|
||||||
|
# Author: Tony DiCola
|
||||||
|
#
|
||||||
|
# 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 FOR 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.
|
||||||
|
from __future__ import division
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
import spidev
|
||||||
|
from smbus import SMBus
|
||||||
|
i2cbus = SMBus(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
SSD1306_I2C_ADDRESS = 0x3C # 011110+SA0+RW - 0x3C or 0x3D
|
||||||
|
SSD1306_SETCONTRAST = 0x81
|
||||||
|
SSD1306_DISPLAYALLON_RESUME = 0xA4
|
||||||
|
SSD1306_DISPLAYALLON = 0xA5
|
||||||
|
SSD1306_NORMALDISPLAY = 0xA6
|
||||||
|
SSD1306_INVERTDISPLAY = 0xA7
|
||||||
|
SSD1306_DISPLAYOFF = 0xAE
|
||||||
|
SSD1306_DISPLAYON = 0xAF
|
||||||
|
SSD1306_SETDISPLAYOFFSET = 0xD3
|
||||||
|
SSD1306_SETCOMPINS = 0xDA
|
||||||
|
SSD1306_SETVCOMDETECT = 0xDB
|
||||||
|
SSD1306_SETDISPLAYCLOCKDIV = 0xD5
|
||||||
|
SSD1306_SETPRECHARGE = 0xD9
|
||||||
|
SSD1306_SETMULTIPLEX = 0xA8
|
||||||
|
SSD1306_SETLOWCOLUMN = 0x00
|
||||||
|
SSD1306_SETHIGHCOLUMN = 0x10
|
||||||
|
SSD1306_SETSTARTLINE = 0x40
|
||||||
|
SSD1306_MEMORYMODE = 0x20
|
||||||
|
SSD1306_COLUMNADDR = 0x21
|
||||||
|
SSD1306_PAGEADDR = 0x22
|
||||||
|
SSD1306_COMSCANINC = 0xC0
|
||||||
|
SSD1306_COMSCANDEC = 0xC8
|
||||||
|
SSD1306_SEGREMAP = 0xA0
|
||||||
|
SSD1306_CHARGEPUMP = 0x8D
|
||||||
|
SSD1306_EXTERNALVCC = 0x1
|
||||||
|
SSD1306_SWITCHCAPVCC = 0x2
|
||||||
|
|
||||||
|
# Scrolling constants
|
||||||
|
SSD1306_ACTIVATE_SCROLL = 0x2F
|
||||||
|
SSD1306_DEACTIVATE_SCROLL = 0x2E
|
||||||
|
SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3
|
||||||
|
SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26
|
||||||
|
SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27
|
||||||
|
SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29
|
||||||
|
SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A
|
||||||
|
|
||||||
|
|
||||||
|
class SSD1306Base(object):
|
||||||
|
"""Base class for SSD1306-based OLED displays. Implementors should subclass
|
||||||
|
and provide an implementation for the _initialize function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, width, height, address=SSD1306_I2C_ADDRESS, bus=None):
|
||||||
|
self._log = logging.getLogger('Adafruit_SSD1306.SSD1306Base')
|
||||||
|
# self._rst = None
|
||||||
|
self.cmd_mode = 0x00
|
||||||
|
self.data_mode = 0x40
|
||||||
|
self.bus = i2cbus
|
||||||
|
self.addr = address
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self._pages = height//8
|
||||||
|
self._buffer = [0]*(width*self._pages)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def command(self, *cmd):
|
||||||
|
"""Send command byte to display."""
|
||||||
|
# I2C write.
|
||||||
|
assert(len(cmd) <= 31)
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
|
||||||
|
|
||||||
|
def data(self, data):
|
||||||
|
"""Send byte of data to display."""
|
||||||
|
# I2C write.
|
||||||
|
for i in range(0, len(data), 31):
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31]))
|
||||||
|
|
||||||
|
def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
|
||||||
|
"""Initialize display."""
|
||||||
|
# Save vcc state.
|
||||||
|
self._vccstate = vccstate
|
||||||
|
# Reset and initialize display.
|
||||||
|
self._initialize()
|
||||||
|
# Turn on the display.
|
||||||
|
self.command(SSD1306_DISPLAYON)
|
||||||
|
|
||||||
|
def ShowImage(self):
|
||||||
|
"""
|
||||||
|
The image on the "canvas" is flushed through to the hardware display.
|
||||||
|
Takes the 1-bit image and dumps it to the SSD1306 OLED display.
|
||||||
|
"""
|
||||||
|
self.command(SSD1306_COLUMNADDR)
|
||||||
|
self.command(0) # Column start address. (0 = reset)
|
||||||
|
self.command(self.width-1) # Column end address.
|
||||||
|
self.command(SSD1306_PAGEADDR)
|
||||||
|
self.command(0) # Page start address. (0 = reset)
|
||||||
|
self.command(self._pages-1) # Page end address.
|
||||||
|
|
||||||
|
for i in range(0, len(self._buffer), 16):
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
"""Set buffer to value of Python Imaging Library image. The image should
|
||||||
|
be in 1 bit mode and a size equal to the display size.
|
||||||
|
"""
|
||||||
|
if image.mode != '1':
|
||||||
|
raise ValueError('Image must be in mode 1.')
|
||||||
|
imwidth, imheight = image.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))
|
||||||
|
# Grab all the pixels from the image, faster than getpixel.
|
||||||
|
pix = image.load()
|
||||||
|
# Iterate through the memory pages
|
||||||
|
index = 0
|
||||||
|
for page in range(self._pages):
|
||||||
|
# Iterate through all x axis columns.
|
||||||
|
for x in range(self.width):
|
||||||
|
# Set the bits for the column of pixels at the current position.
|
||||||
|
bits = 0
|
||||||
|
# Don't use range here as it's a bit slow
|
||||||
|
for bit in [0, 1, 2, 3, 4, 5, 6, 7]:
|
||||||
|
bits = bits << 1
|
||||||
|
bits |= 0 if pix[(x, page*8+7-bit)] == 0 else 1
|
||||||
|
# Update buffer byte and increment to next byte.
|
||||||
|
self._buffer[index] = bits
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Clear contents of image buffer."""
|
||||||
|
self._buffer = [0]*(self.width*self._pages)
|
||||||
|
|
||||||
|
def set_contrast(self, contrast):
|
||||||
|
"""Sets the contrast of the display. Contrast should be a value between
|
||||||
|
0 and 255."""
|
||||||
|
if contrast < 0 or contrast > 255:
|
||||||
|
raise ValueError('Contrast must be a value from 0 to 255 (inclusive).')
|
||||||
|
self.command(SSD1306_SETCONTRAST)
|
||||||
|
self.command(contrast)
|
||||||
|
|
||||||
|
def dim(self, dim):
|
||||||
|
"""Adjusts contrast to dim the display if dim is True, otherwise sets the
|
||||||
|
contrast to normal brightness if dim is False.
|
||||||
|
"""
|
||||||
|
# Assume dim display.
|
||||||
|
contrast = 0
|
||||||
|
# Adjust contrast based on VCC if not dimming.
|
||||||
|
if not dim:
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
contrast = 0x9F
|
||||||
|
else:
|
||||||
|
contrast = 0xCF
|
||||||
|
self.set_contrast(contrast)
|
||||||
|
|
||||||
|
class SSD1306_128_64(SSD1306Base):
|
||||||
|
def __init__(self, width, height, address=None, bus=None):
|
||||||
|
# Call base class constructor.
|
||||||
|
super(SSD1306_128_64, self).__init__(128, 64, address, bus)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
# 128x64 pixel specific initialization.
|
||||||
|
self.command(SSD1306_DISPLAYOFF) # 0xAE
|
||||||
|
self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5
|
||||||
|
self.command(0x80) # the suggested ratio 0x80
|
||||||
|
self.command(SSD1306_SETMULTIPLEX) # 0xA8
|
||||||
|
self.command(0x3F)
|
||||||
|
self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3
|
||||||
|
self.command(0x0) # no offset
|
||||||
|
self.command(SSD1306_SETSTARTLINE | 0x0) # line #0
|
||||||
|
self.command(SSD1306_CHARGEPUMP) # 0x8D
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x10)
|
||||||
|
else:
|
||||||
|
self.command(0x14)
|
||||||
|
self.command(SSD1306_MEMORYMODE) # 0x20
|
||||||
|
self.command(0x00) # 0x0 act like ks0108
|
||||||
|
self.command(SSD1306_SEGREMAP | 0x1)
|
||||||
|
self.command(SSD1306_COMSCANDEC)
|
||||||
|
self.command(SSD1306_SETCOMPINS) # 0xDA
|
||||||
|
self.command(0x12)
|
||||||
|
self.command(SSD1306_SETCONTRAST) # 0x81
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x9F)
|
||||||
|
else:
|
||||||
|
self.command(0xCF)
|
||||||
|
self.command(SSD1306_SETPRECHARGE) # 0xd9
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x22)
|
||||||
|
else:
|
||||||
|
self.command(0xF1)
|
||||||
|
self.command(SSD1306_SETVCOMDETECT) # 0xDB
|
||||||
|
self.command(0x40)
|
||||||
|
self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4
|
||||||
|
self.command(SSD1306_NORMALDISPLAY) # 0xA6
|
||||||
|
|
||||||
|
class SSD1306_128_32(SSD1306Base):
|
||||||
|
def __init__(self, width, height, address=None, bus=None):
|
||||||
|
# Call base class constructor.
|
||||||
|
super(SSD1306_128_64, self).__init__(128, 64, address, bus)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
# 128x32 pixel specific initialization.
|
||||||
|
self.command(SSD1306_DISPLAYOFF) # 0xAE
|
||||||
|
self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5
|
||||||
|
self.command(0x80) # the suggested ratio 0x80
|
||||||
|
self.command(SSD1306_SETMULTIPLEX) # 0xA8
|
||||||
|
self.command(0x1F)
|
||||||
|
self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3
|
||||||
|
self.command(0x0) # no offset
|
||||||
|
self.command(SSD1306_SETSTARTLINE | 0x0) # line #0
|
||||||
|
self.command(SSD1306_CHARGEPUMP) # 0x8D
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x10)
|
||||||
|
else:
|
||||||
|
self.command(0x14)
|
||||||
|
self.command(SSD1306_MEMORYMODE) # 0x20
|
||||||
|
self.command(0x00) # 0x0 act like ks0108
|
||||||
|
self.command(SSD1306_SEGREMAP | 0x1)
|
||||||
|
self.command(SSD1306_COMSCANDEC)
|
||||||
|
self.command(SSD1306_SETCOMPINS) # 0xDA
|
||||||
|
self.command(0x02)
|
||||||
|
self.command(SSD1306_SETCONTRAST) # 0x81
|
||||||
|
self.command(0x8F)
|
||||||
|
self.command(SSD1306_SETPRECHARGE) # 0xd9
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x22)
|
||||||
|
else:
|
||||||
|
self.command(0xF1)
|
||||||
|
self.command(SSD1306_SETVCOMDETECT) # 0xDB
|
||||||
|
self.command(0x40)
|
||||||
|
self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4
|
||||||
|
self.command(SSD1306_NORMALDISPLAY) # 0xA6
|
||||||
|
|
||||||
|
|
||||||
|
class SSD1306_96_16(SSD1306Base):
|
||||||
|
def __init__(self, width, height, address=None, bus=None):
|
||||||
|
# Call base class constructor.
|
||||||
|
super(SSD1306_96_16, self).__init__(96, 16, address, bus)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
# 128x32 pixel specific initialization.
|
||||||
|
self.command(SSD1306_DISPLAYOFF) # 0xAE
|
||||||
|
self.command(SSD1306_SETDISPLAYCLOCKDIV) # 0xD5
|
||||||
|
self.command(0x60) # the suggested ratio 0x60
|
||||||
|
self.command(SSD1306_SETMULTIPLEX) # 0xA8
|
||||||
|
self.command(0x0F)
|
||||||
|
self.command(SSD1306_SETDISPLAYOFFSET) # 0xD3
|
||||||
|
self.command(0x0) # no offset
|
||||||
|
self.command(SSD1306_SETSTARTLINE | 0x0) # line #0
|
||||||
|
self.command(SSD1306_CHARGEPUMP) # 0x8D
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x10)
|
||||||
|
else:
|
||||||
|
self.command(0x14)
|
||||||
|
self.command(SSD1306_MEMORYMODE) # 0x20
|
||||||
|
self.command(0x00) # 0x0 act like ks0108
|
||||||
|
self.command(SSD1306_SEGREMAP | 0x1)
|
||||||
|
self.command(SSD1306_COMSCANDEC)
|
||||||
|
self.command(SSD1306_SETCOMPINS) # 0xDA
|
||||||
|
self.command(0x02)
|
||||||
|
self.command(SSD1306_SETCONTRAST) # 0x81
|
||||||
|
self.command(0x8F)
|
||||||
|
self.command(SSD1306_SETPRECHARGE) # 0xd9
|
||||||
|
if self._vccstate == SSD1306_EXTERNALVCC:
|
||||||
|
self.command(0x22)
|
||||||
|
else:
|
||||||
|
self.command(0xF1)
|
||||||
|
self.command(SSD1306_SETVCOMDETECT) # 0xDB
|
||||||
|
self.command(0x40)
|
||||||
|
self.command(SSD1306_DISPLAYALLON_RESUME) # 0xA4
|
||||||
|
self.command(SSD1306_NORMALDISPLAY) # 0xA6
|
352
pwnagotchi/ui/hw/libs/waveshare/oled/oledlcd/ST7789vert.py
Normal file
352
pwnagotchi/ui/hw/libs/waveshare/oled/oledlcd/ST7789vert.py
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
# Copyright (c) 2014 Adafruit Industries
|
||||||
|
# Author: Tony DiCola
|
||||||
|
#
|
||||||
|
# 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 FOR 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 numbers
|
||||||
|
import time
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import spidev
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
|
|
||||||
|
__version__ = '0.0.4'
|
||||||
|
|
||||||
|
BG_SPI_CS_BACK = 0
|
||||||
|
BG_SPI_CS_FRONT = 1
|
||||||
|
|
||||||
|
SPI_CLOCK_HZ = 16000000
|
||||||
|
|
||||||
|
ST7789_NOP = 0x00
|
||||||
|
ST7789_SWRESET = 0x01
|
||||||
|
ST7789_RDDID = 0x04
|
||||||
|
ST7789_RDDST = 0x09
|
||||||
|
|
||||||
|
ST7789_SLPIN = 0x10
|
||||||
|
ST7789_SLPOUT = 0x11
|
||||||
|
ST7789_PTLON = 0x12
|
||||||
|
ST7789_NORON = 0x13
|
||||||
|
|
||||||
|
ST7789_INVOFF = 0x20
|
||||||
|
ST7789_INVON = 0x21
|
||||||
|
ST7789_DISPOFF = 0x28
|
||||||
|
ST7789_DISPON = 0x29
|
||||||
|
|
||||||
|
ST7789_CASET = 0x2A
|
||||||
|
ST7789_RASET = 0x2B
|
||||||
|
ST7789_RAMWR = 0x2C
|
||||||
|
ST7789_RAMRD = 0x2E
|
||||||
|
|
||||||
|
ST7789_PTLAR = 0x30
|
||||||
|
ST7789_MADCTL = 0x36
|
||||||
|
ST7789_COLMOD = 0x3A
|
||||||
|
|
||||||
|
ST7789_FRMCTR1 = 0xB1
|
||||||
|
ST7789_FRMCTR2 = 0xB2
|
||||||
|
ST7789_FRMCTR3 = 0xB3
|
||||||
|
ST7789_INVCTR = 0xB4
|
||||||
|
ST7789_DISSET5 = 0xB6
|
||||||
|
|
||||||
|
ST7789_GCTRL = 0xB7
|
||||||
|
ST7789_GTADJ = 0xB8
|
||||||
|
ST7789_VCOMS = 0xBB
|
||||||
|
|
||||||
|
ST7789_LCMCTRL = 0xC0
|
||||||
|
ST7789_IDSET = 0xC1
|
||||||
|
ST7789_VDVVRHEN = 0xC2
|
||||||
|
ST7789_VRHS = 0xC3
|
||||||
|
ST7789_VDVS = 0xC4
|
||||||
|
ST7789_VMCTR1 = 0xC5
|
||||||
|
ST7789_FRCTRL2 = 0xC6
|
||||||
|
ST7789_CABCCTRL = 0xC7
|
||||||
|
|
||||||
|
ST7789_RDID1 = 0xDA
|
||||||
|
ST7789_RDID2 = 0xDB
|
||||||
|
ST7789_RDID3 = 0xDC
|
||||||
|
ST7789_RDID4 = 0xDD
|
||||||
|
|
||||||
|
ST7789_GMCTRP1 = 0xE0
|
||||||
|
ST7789_GMCTRN1 = 0xE1
|
||||||
|
|
||||||
|
ST7789_PWCTR6 = 0xFC
|
||||||
|
|
||||||
|
|
||||||
|
class ST7789(object):
|
||||||
|
"""Representation of an ST7789 TFT LCD."""
|
||||||
|
|
||||||
|
def __init__(self, port, cs, dc, backlight, rst=None, width=320,
|
||||||
|
height=240, rotation=270, invert=True, spi_speed_hz=60 * 1000 * 1000,
|
||||||
|
offset_left=0,
|
||||||
|
offset_top=0):
|
||||||
|
"""Create an instance of the display using SPI communication.
|
||||||
|
Must provide the GPIO pin number for the D/C pin and the SPI driver.
|
||||||
|
Can optionally provide the GPIO pin number for the reset pin as the rst parameter.
|
||||||
|
:param port: SPI port number
|
||||||
|
:param cs: SPI chip-select number (0 or 1 for BCM
|
||||||
|
:param backlight: Pin for controlling backlight
|
||||||
|
:param rst: Reset pin for ST7789
|
||||||
|
:param width: Width of display connected to ST7789
|
||||||
|
:param height: Height of display connected to ST7789
|
||||||
|
:param rotation: Rotation of display connected to ST7789
|
||||||
|
:param invert: Invert display
|
||||||
|
:param spi_speed_hz: SPI speed (in Hz)
|
||||||
|
"""
|
||||||
|
if rotation not in [0, 90, 180, 270]:
|
||||||
|
raise ValueError("Invalid rotation {}".format(rotation))
|
||||||
|
|
||||||
|
# if width != height and rotation in [90, 270]:
|
||||||
|
# raise ValueError("Invalid rotation {} for {}x{} resolution".format(rotation, width, height))
|
||||||
|
|
||||||
|
GPIO.setwarnings(False)
|
||||||
|
GPIO.setmode(GPIO.BCM)
|
||||||
|
|
||||||
|
self._spi = spidev.SpiDev(port, cs)
|
||||||
|
self._spi.mode = 0
|
||||||
|
self._spi.lsbfirst = False
|
||||||
|
self._spi.max_speed_hz = spi_speed_hz
|
||||||
|
|
||||||
|
self._dc = dc
|
||||||
|
self._rst = rst
|
||||||
|
self._width = width
|
||||||
|
self._height = height
|
||||||
|
self._rotation = rotation
|
||||||
|
self._invert = invert
|
||||||
|
|
||||||
|
self._offset_left = offset_left
|
||||||
|
self._offset_top = offset_top
|
||||||
|
|
||||||
|
# Set DC as output.
|
||||||
|
GPIO.setup(dc, GPIO.OUT)
|
||||||
|
|
||||||
|
# Setup backlight as output (if provided).
|
||||||
|
self._backlight = backlight
|
||||||
|
if backlight is not None:
|
||||||
|
GPIO.setup(backlight, GPIO.OUT)
|
||||||
|
GPIO.output(backlight, GPIO.LOW)
|
||||||
|
time.sleep(0.1)
|
||||||
|
GPIO.output(backlight, GPIO.HIGH)
|
||||||
|
|
||||||
|
# Setup reset as output (if provided).
|
||||||
|
if rst is not None:
|
||||||
|
GPIO.setup(self._rst, GPIO.OUT)
|
||||||
|
self.reset()
|
||||||
|
self._init()
|
||||||
|
|
||||||
|
def send(self, data, is_data=True, chunk_size=4096):
|
||||||
|
"""Write a byte or array of bytes to the display. Is_data parameter
|
||||||
|
controls if byte should be interpreted as display data (True) or command
|
||||||
|
data (False). Chunk_size is an optional size of bytes to write in a
|
||||||
|
single SPI transaction, with a default of 4096.
|
||||||
|
"""
|
||||||
|
# Set DC low for command, high for data.
|
||||||
|
GPIO.output(self._dc, is_data)
|
||||||
|
# Convert scalar argument to list so either can be passed as parameter.
|
||||||
|
if isinstance(data, numbers.Number):
|
||||||
|
data = [data & 0xFF]
|
||||||
|
# Write data a chunk at a time.
|
||||||
|
for start in range(0, len(data), chunk_size):
|
||||||
|
end = min(start + chunk_size, len(data))
|
||||||
|
self._spi.xfer(data[start:end])
|
||||||
|
|
||||||
|
def set_backlight(self, value):
|
||||||
|
"""Set the backlight on/off."""
|
||||||
|
if self._backlight is not None:
|
||||||
|
GPIO.output(self._backlight, value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self):
|
||||||
|
return self._width if self._rotation == 0 or self._rotation == 180 else self._height
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
return self._height if self._rotation == 0 or self._rotation == 180 else self._width
|
||||||
|
|
||||||
|
def command(self, data):
|
||||||
|
"""Write a byte or array of bytes to the display as command data."""
|
||||||
|
self.send(data, False)
|
||||||
|
|
||||||
|
def data(self, data):
|
||||||
|
"""Write a byte or array of bytes to the display as display data."""
|
||||||
|
self.send(data, True)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Reset the display, if reset pin is connected."""
|
||||||
|
if self._rst is not None:
|
||||||
|
GPIO.output(self._rst, 1)
|
||||||
|
time.sleep(0.500)
|
||||||
|
GPIO.output(self._rst, 0)
|
||||||
|
time.sleep(0.500)
|
||||||
|
GPIO.output(self._rst, 1)
|
||||||
|
time.sleep(0.500)
|
||||||
|
|
||||||
|
def _init(self):
|
||||||
|
# Initialize the display.
|
||||||
|
|
||||||
|
self.command(ST7789_SWRESET) # Software reset
|
||||||
|
time.sleep(0.150) # delay 150 ms
|
||||||
|
|
||||||
|
self.command(ST7789_MADCTL)
|
||||||
|
self.data(0x70)
|
||||||
|
|
||||||
|
self.command(ST7789_FRMCTR2) # Frame rate ctrl - idle mode
|
||||||
|
self.data(0x0C)
|
||||||
|
self.data(0x0C)
|
||||||
|
self.data(0x00)
|
||||||
|
self.data(0x33)
|
||||||
|
self.data(0x33)
|
||||||
|
|
||||||
|
self.command(ST7789_COLMOD)
|
||||||
|
self.data(0x05)
|
||||||
|
|
||||||
|
self.command(ST7789_GCTRL)
|
||||||
|
self.data(0x14)
|
||||||
|
|
||||||
|
self.command(ST7789_VCOMS)
|
||||||
|
self.data(0x37)
|
||||||
|
|
||||||
|
self.command(ST7789_LCMCTRL) # Power control
|
||||||
|
self.data(0x2C)
|
||||||
|
|
||||||
|
self.command(ST7789_VDVVRHEN) # Power control
|
||||||
|
self.data(0x01)
|
||||||
|
|
||||||
|
self.command(ST7789_VRHS) # Power control
|
||||||
|
self.data(0x12)
|
||||||
|
|
||||||
|
self.command(ST7789_VDVS) # Power control
|
||||||
|
self.data(0x20)
|
||||||
|
|
||||||
|
self.command(0xD0)
|
||||||
|
self.data(0xA4)
|
||||||
|
self.data(0xA1)
|
||||||
|
|
||||||
|
self.command(ST7789_FRCTRL2)
|
||||||
|
self.data(0x0F)
|
||||||
|
|
||||||
|
self.command(ST7789_GMCTRP1) # Set Gamma
|
||||||
|
self.data(0xD0)
|
||||||
|
self.data(0x04)
|
||||||
|
self.data(0x0D)
|
||||||
|
self.data(0x11)
|
||||||
|
self.data(0x13)
|
||||||
|
self.data(0x2B)
|
||||||
|
self.data(0x3F)
|
||||||
|
self.data(0x54)
|
||||||
|
self.data(0x4C)
|
||||||
|
self.data(0x18)
|
||||||
|
self.data(0x0D)
|
||||||
|
self.data(0x0B)
|
||||||
|
self.data(0x1F)
|
||||||
|
self.data(0x23)
|
||||||
|
|
||||||
|
self.command(ST7789_GMCTRN1) # Set Gamma
|
||||||
|
self.data(0xD0)
|
||||||
|
self.data(0x04)
|
||||||
|
self.data(0x0C)
|
||||||
|
self.data(0x11)
|
||||||
|
self.data(0x13)
|
||||||
|
self.data(0x2C)
|
||||||
|
self.data(0x3F)
|
||||||
|
self.data(0x44)
|
||||||
|
self.data(0x51)
|
||||||
|
self.data(0x2F)
|
||||||
|
self.data(0x1F)
|
||||||
|
self.data(0x1F)
|
||||||
|
self.data(0x20)
|
||||||
|
self.data(0x23)
|
||||||
|
|
||||||
|
if self._invert:
|
||||||
|
self.command(ST7789_INVON) # Invert display
|
||||||
|
else:
|
||||||
|
self.command(ST7789_INVOFF) # Don't invert display
|
||||||
|
|
||||||
|
self.command(ST7789_SLPOUT)
|
||||||
|
|
||||||
|
self.command(ST7789_DISPON) # Display on
|
||||||
|
time.sleep(0.100) # 100 ms
|
||||||
|
|
||||||
|
def begin(self):
|
||||||
|
"""Set up the display
|
||||||
|
Deprecated. Included in __init__.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_window(self, x0=0, y0=0, x1=None, y1=None):
|
||||||
|
"""Set the pixel address window for proceeding drawing commands. x0 and
|
||||||
|
x1 should define the minimum and maximum x pixel bounds. y0 and y1
|
||||||
|
should define the minimum and maximum y pixel bound. If no parameters
|
||||||
|
are specified the default will be to update the entire display from 0,0
|
||||||
|
to width-1,height-1.
|
||||||
|
"""
|
||||||
|
if x1 is None:
|
||||||
|
x1 = self._width - 1
|
||||||
|
|
||||||
|
if y1 is None:
|
||||||
|
y1 = self._height - 1
|
||||||
|
|
||||||
|
y0 += self._offset_top
|
||||||
|
y1 += self._offset_top
|
||||||
|
|
||||||
|
x0 += self._offset_left
|
||||||
|
x1 += self._offset_left
|
||||||
|
|
||||||
|
self.command(ST7789_CASET) # Column addr set
|
||||||
|
self.data(x0 >> 8)
|
||||||
|
self.data(x0 & 0xFF) # XSTART
|
||||||
|
self.data(x1 >> 8)
|
||||||
|
self.data(x1 & 0xFF) # XEND
|
||||||
|
self.command(ST7789_RASET) # Row addr set
|
||||||
|
self.data(y0 >> 8)
|
||||||
|
self.data(y0 & 0xFF) # YSTART
|
||||||
|
self.data(y1 >> 8)
|
||||||
|
self.data(y1 & 0xFF) # YEND
|
||||||
|
self.command(ST7789_RAMWR) # write to RAM
|
||||||
|
|
||||||
|
def display(self, image):
|
||||||
|
"""Write the provided image to the hardware.
|
||||||
|
:param image: Should be RGB format and the same dimensions as the display hardware.
|
||||||
|
"""
|
||||||
|
# Set address bounds to entire display.
|
||||||
|
self.set_window()
|
||||||
|
|
||||||
|
# Convert image to 16bit RGB565 format and
|
||||||
|
# flatten into bytes.
|
||||||
|
pixelbytes = self.image_to_data(image, self._rotation)
|
||||||
|
|
||||||
|
# Write data to hardware.
|
||||||
|
for i in range(0, len(pixelbytes), 4096):
|
||||||
|
self.data(pixelbytes[i:i + 4096])
|
||||||
|
|
||||||
|
def image_to_data(self, image, rotation=0):
|
||||||
|
if not isinstance(image, np.ndarray):
|
||||||
|
image = np.array(image.convert('RGB'))
|
||||||
|
|
||||||
|
# Rotate the image
|
||||||
|
pb = np.rot90(image, rotation // 90).astype('uint16')
|
||||||
|
|
||||||
|
# Mask and shift the 888 RGB into 565 RGB
|
||||||
|
red = (pb[..., [0]] & 0xf8) << 8
|
||||||
|
green = (pb[..., [1]] & 0xfc) << 3
|
||||||
|
blue = (pb[..., [2]] & 0xf8) >> 3
|
||||||
|
|
||||||
|
# Stick 'em together
|
||||||
|
result = red | green | blue
|
||||||
|
|
||||||
|
# Output the raw bytes
|
||||||
|
return result.byteswap().tobytes()
|
23
pwnagotchi/ui/hw/libs/waveshare/oled/oledlcd/epd.py
Normal file
23
pwnagotchi/ui/hw/libs/waveshare/oled/oledlcd/epd.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from . import SSD1306
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 128
|
||||||
|
EPD_HEIGHT = 64
|
||||||
|
|
||||||
|
disp = SSD1306.SSD1306_128_64(128, 64, address=0x3C)
|
||||||
|
|
||||||
|
class EPD(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
def Init(self):
|
||||||
|
disp.begin()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
disp.clear()
|
||||||
|
|
||||||
|
def display(self, image):
|
||||||
|
disp.getbuffer(image)
|
||||||
|
disp.ShowImage()
|
59
pwnagotchi/ui/hw/waveshareoledlcdvert.py
Normal file
59
pwnagotchi/ui/hw/waveshareoledlcdvert.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# workinprogress based on the displayhatmini driver
|
||||||
|
# LCD support OK
|
||||||
|
# OLED support ongoing
|
||||||
|
# board GPIO:
|
||||||
|
# Key1: GPIO4 / pin7
|
||||||
|
# Key2: GPIO17 / pin11
|
||||||
|
# Key3: GPIO23 / pin16
|
||||||
|
# Key4: GPIO24 / pin18
|
||||||
|
# OLED SDA: GPIO2 / pin3
|
||||||
|
# OLED SCL: GPIO3 / pin5
|
||||||
|
# OLED info:
|
||||||
|
# driver: SSD1315 (I2C)
|
||||||
|
# resolution: 128x64
|
||||||
|
# I2C address: 0x3C 0x3D
|
||||||
|
# HW datasheet: https://www.waveshare.com/wiki/OLED/LCD_HAT_(A)
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import pwnagotchi.ui.fonts as fonts
|
||||||
|
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||||
|
|
||||||
|
|
||||||
|
class Waveshareoledlcdvert(DisplayImpl):
|
||||||
|
def __init__(self, config):
|
||||||
|
super(Waveshareoledlcdvert, self).__init__(config, 'waveshareoledlcdvert')
|
||||||
|
|
||||||
|
def layout(self):
|
||||||
|
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||||
|
self._layout['width'] = 240
|
||||||
|
self._layout['height'] = 320
|
||||||
|
self._layout['face'] = (0, 40)
|
||||||
|
self._layout['name'] = (5, 20)
|
||||||
|
self._layout['channel'] = (0, 0)
|
||||||
|
self._layout['aps'] = (28, 0)
|
||||||
|
self._layout['uptime'] = (175, 0)
|
||||||
|
self._layout['line1'] = [0, 14, 240, 14]
|
||||||
|
self._layout['line2'] = [0, 108, 240, 108]
|
||||||
|
self._layout['friend_face'] = (0, 92)
|
||||||
|
self._layout['friend_name'] = (40, 94)
|
||||||
|
self._layout['shakes'] = (0, 109)
|
||||||
|
self._layout['mode'] = (215, 109)
|
||||||
|
self._layout['status'] = {
|
||||||
|
'pos': (125, 20),
|
||||||
|
'font': fonts.status_font(fonts.Medium),
|
||||||
|
'max': 20
|
||||||
|
}
|
||||||
|
|
||||||
|
return self._layout
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
logging.info("initializing Waveshare OLED/LCD hat vertical mode")
|
||||||
|
from pwnagotchi.ui.hw.libs.waveshare.oled.oledlcd.ST7789vert import ST7789
|
||||||
|
self._display = ST7789(0,0,22,18)
|
||||||
|
|
||||||
|
def render(self, canvas):
|
||||||
|
self._display.display(canvas)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self._display.clear()
|
@ -32,13 +32,10 @@ class View(object):
|
|||||||
logging.debug("INVERT BLACK/WHITES:" + str(config['ui']['invert']))
|
logging.debug("INVERT BLACK/WHITES:" + str(config['ui']['invert']))
|
||||||
self.invert = 1
|
self.invert = 1
|
||||||
BLACK = 0x00
|
BLACK = 0x00
|
||||||
WHITE - 0xFF
|
WHITE = 0xFF
|
||||||
self._black = 0x00
|
self._black = 0x00
|
||||||
self._white = 0xFF
|
self._white = 0xFF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# setup faces from the configuration in case the user customized them
|
# setup faces from the configuration in case the user customized them
|
||||||
faces.load_from_config(config['ui']['faces'])
|
faces.load_from_config(config['ui']['faces'])
|
||||||
|
|
||||||
@ -112,7 +109,7 @@ class View(object):
|
|||||||
self._state.has_element(key)
|
self._state.has_element(key)
|
||||||
|
|
||||||
def add_element(self, key, elem):
|
def add_element(self, key, elem):
|
||||||
if self.invert is 1 and elem.color:
|
if self.invert is 1 and hasattr(elem, 'color'):
|
||||||
if elem.color == 0xff:
|
if elem.color == 0xff:
|
||||||
elem.color = 0x00
|
elem.color = 0x00
|
||||||
elif elem.color == 0x00:
|
elif elem.color == 0x00:
|
||||||
|
@ -315,9 +315,15 @@ def load_config(args):
|
|||||||
elif config['ui']['display']['type'] in ('waveshareoledlcd'):
|
elif config['ui']['display']['type'] in ('waveshareoledlcd'):
|
||||||
config['ui']['display']['type'] = 'waveshareoledlcd'
|
config['ui']['display']['type'] = 'waveshareoledlcd'
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] in ('i2coled'):
|
||||||
|
config['ui']['display']['type'] = 'i2coled'
|
||||||
|
|
||||||
elif config['ui']['display']['type'] in ('waveshare35lcd'):
|
elif config['ui']['display']['type'] in ('waveshare35lcd'):
|
||||||
config['ui']['display']['type'] = 'waveshare35lcd'
|
config['ui']['display']['type'] = 'waveshare35lcd'
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] in ('waveshareoledlcdvert'):
|
||||||
|
config['ui']['display']['type'] = 'waveshareoledlcdvert'
|
||||||
|
|
||||||
# E-INK DISPLAYS ------------------------------------------------------------------------
|
# E-INK DISPLAYS ------------------------------------------------------------------------
|
||||||
|
|
||||||
# Adafruit
|
# Adafruit
|
||||||
|
@ -8,7 +8,7 @@ dynamic = ["version"]
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"Pillow",
|
"Pillow",
|
||||||
"PyYAML",
|
"PyYAML",
|
||||||
"RPi.GPIO",
|
"rpi.lgpio",
|
||||||
"dbus-python",
|
"dbus-python",
|
||||||
"file-read-backwards",
|
"file-read-backwards",
|
||||||
"flask",
|
"flask",
|
||||||
@ -29,8 +29,8 @@ dependencies = [
|
|||||||
"spidev",
|
"spidev",
|
||||||
"stable_baselines3",
|
"stable_baselines3",
|
||||||
"toml",
|
"toml",
|
||||||
"torch",
|
"torch; platform_machine=='aarch64'",
|
||||||
"torchvision",
|
"torchvision; platform_machine=='aarch64'",
|
||||||
"tweepy",
|
"tweepy",
|
||||||
"websockets",
|
"websockets",
|
||||||
]
|
]
|
||||||
|
@ -18,9 +18,7 @@ dbus-python
|
|||||||
toml
|
toml
|
||||||
python-dateutil
|
python-dateutil
|
||||||
websockets
|
websockets
|
||||||
torch
|
|
||||||
torchvision
|
|
||||||
stable_baselines3
|
stable_baselines3
|
||||||
RPi.GPIO
|
rpi-lgpio
|
||||||
rpi_hardware_pwm
|
rpi_hardware_pwm
|
||||||
pydrive2
|
pydrive2
|
Reference in New Issue
Block a user