Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c12b319287 | ||
|
712d0142a1 | ||
|
9ba55b7f77 | ||
|
abc16ce973 | ||
|
1318275b36 | ||
|
297d9cd3b9 | ||
|
f164b8bb26 | ||
|
5c3b21f537 | ||
|
6325428218 | ||
|
7d35f5cdc0 | ||
|
3fd3ac3c01 | ||
|
c1d3528ff7 | ||
|
37fc65f834 | ||
|
80095edf4b | ||
|
7e3e74635a | ||
|
6b3d9042fd | ||
|
4441ae852c | ||
|
edc0551e0a | ||
|
b6cf510f8e | ||
|
7fb6be861a | ||
|
f795598950 | ||
|
b0efd52961 | ||
|
38dfccb7c2 | ||
|
f912883f6e | ||
|
661f26dedf | ||
|
d6c7a73f39 | ||
|
10f274dab7 | ||
|
decbeaccb1 | ||
|
34c2c8a06e | ||
|
88a15528d6 | ||
|
0fd09878db | ||
|
c472e60615 | ||
|
0704541dd1 | ||
|
ea061d473b | ||
|
6430a40847 | ||
|
ba13b12593 | ||
|
819be761ed | ||
|
f701390d5a | ||
|
2ddf040fac | ||
|
3bd9cd4f18 | ||
|
5c6d8dc807 | ||
|
c535ffd40e | ||
|
fb7217b0fa | ||
|
7da3cc5565 | ||
|
e72e2292a8 | ||
|
0f8643258e | ||
|
1a0083eb38 | ||
|
72878454f9 | ||
|
1c4df7a1c4 | ||
|
c124a97514 | ||
|
b886b4e673 | ||
|
6d0e295276 | ||
|
1aea0b95b1 | ||
|
fddee8708e | ||
|
ef4fbd96cc | ||
|
552df65422 | ||
|
2db8f143eb | ||
|
6111ee9d9d | ||
|
713a14c504 | ||
|
2708fd032c | ||
|
f7cf4b3947 | ||
|
1d312a727b | ||
|
dd3dbbe400 | ||
|
cfa034b555 | ||
|
a0cd0d4936 | ||
|
3e3fff298c | ||
|
0b1c51dcc7 | ||
|
8dd9a85615 | ||
|
929eac7bba | ||
|
0f7870f770 | ||
|
37342c0685 | ||
|
71514a97fa | ||
|
03488819af | ||
|
633b726bcd | ||
|
05b235c38b | ||
|
840054f549 | ||
|
a3cf49244e | ||
|
e92751164f | ||
|
c2f9860bc5 | ||
|
f616871068 | ||
|
c726779f6e | ||
|
a2e29d64d2 | ||
|
bc84f22f7a | ||
|
40d8d994d1 | ||
|
7ca5eee247 | ||
|
56c291d302 | ||
|
1013e7dc19 | ||
|
ff4f5c672a | ||
|
d9d268ea81 | ||
|
de62214970 | ||
|
52cc413152 | ||
|
716d5cd312 | ||
|
e436dc8b8e | ||
|
81db495f33 | ||
|
7f8380c38a | ||
|
8c2b4e2075 | ||
|
2b17e5322b | ||
|
1be17b1f99 | ||
|
2dee3987d4 | ||
|
eb76cc7023 | ||
|
35ea36ef33 | ||
|
44e1e79245 | ||
|
6038f555fa | ||
|
0b5a63a3d8 | ||
|
430172e3dd | ||
|
fa87e03222 | ||
|
d1411ffa96 | ||
|
67b4747afa | ||
|
311931c81d | ||
|
5f7dd56ead |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -18,3 +18,12 @@ pwnagotchi.egg-info
|
||||
*backup*.tgz
|
||||
*backup*.gz
|
||||
.vscode
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
8
Makefile
8
Makefile
@@ -1,9 +1,15 @@
|
||||
PACKER_VERSION=1.5.2
|
||||
PACKER_VERSION=1.7.2
|
||||
PWN_HOSTNAME=pwnagotchi
|
||||
PWN_VERSION=master
|
||||
|
||||
all: clean install image
|
||||
|
||||
langs:
|
||||
@for lang in pwnagotchi/locale/*/; do\
|
||||
echo "compiling language: $$lang ..."; \
|
||||
./scripts/language.sh compile $$(basename $$lang); \
|
||||
done
|
||||
|
||||
install:
|
||||
curl https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_amd64.zip -o /tmp/packer.zip
|
||||
unzip /tmp/packer.zip -d /tmp
|
||||
|
@@ -15,7 +15,7 @@ full and half WPA handshakes.
|
||||
|
||||

|
||||
|
||||
Instead of merely playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced) like most reinforcement learning-based "AI" *(yawn)*, Pwnagotchi tunes [its parameters](https://github.com/evilsocket/pwnagotchi/blob/master/pwnagotchi/defaults.yml#L73) over time to **get better at pwning WiFi things to** in the environments you expose it to.
|
||||
Instead of merely playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced) like most reinforcement learning-based "AI" *(yawn)*, Pwnagotchi tunes [its parameters](https://github.com/evilsocket/pwnagotchi/blob/master/pwnagotchi/defaults.toml) over time to **get better at pwning WiFi things to** in the environments you expose it to.
|
||||
|
||||
More specifically, Pwnagotchi is using an [LSTM with MLP feature extractor](https://stable-baselines.readthedocs.io/en/master/modules/policies.html#stable_baselines.common.policies.MlpLstmPolicy) as its policy network for the [A2C agent](https://stable-baselines.readthedocs.io/en/master/modules/a2c.html). If you're unfamiliar with A2C, here is [a very good introductory explanation](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752) (in comic form!) of the basic principles behind how Pwnagotchi learns. (You can read more about how Pwnagotchi learns in the [Usage](https://www.pwnagotchi.ai/usage/#training-the-ai) doc.)
|
||||
|
||||
|
29
builder/data/etc/bash_completion.d/pwnagotchi_completion.sh
Normal file
29
builder/data/etc/bash_completion.d/pwnagotchi_completion.sh
Normal file
@@ -0,0 +1,29 @@
|
||||
_show_complete()
|
||||
{
|
||||
local cur opts node_names all_options opt_line
|
||||
all_options="
|
||||
pwnagotchi -h --help -C --config -U --user-config --manual --skip-session --clear --debug --version --print-config {plugins}
|
||||
pwnagotchi plugins -h --help {list,install,enable,disable,uninstall,update,upgrade}
|
||||
pwnagotchi plugins list -i --installed -h --help
|
||||
pwnagotchi plugins install -h --help
|
||||
pwnagotchi plugins uninstall -h --help
|
||||
pwnagotchi plugins enable -h --help
|
||||
pwnagotchi plugins disable -h --help
|
||||
pwnagotchi plugins update -h --help
|
||||
pwnagotchi plugins upgrade -h --help
|
||||
"
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
cmd="${COMP_WORDS[@]:0:${#COMP_WORDS[@]}-1}"
|
||||
opt_line="$(grep -m1 "$cmd" <<<$all_options)"
|
||||
if [[ ${cur} == -* ]] ; then
|
||||
opts="$(echo $opt_line | tr ' ' '\n' | awk '/^ *-/{gsub("[^a-zA-Z0-9-]","",$1);print $1}')"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
fi
|
||||
|
||||
opts="$(echo $opt_line | grep -Po '{\K[^}]+' | tr ',' '\n')"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
}
|
||||
|
||||
complete -F _show_complete pwnagotchi
|
@@ -4,4 +4,5 @@ iface usb0 inet static
|
||||
netmask 255.255.255.0
|
||||
network 10.0.0.0
|
||||
broadcast 10.0.0.255
|
||||
gateway 10.0.0.1
|
||||
gateway 10.0.0.1
|
||||
metric 20
|
||||
|
@@ -9,6 +9,15 @@ if is_crypted_mode; then
|
||||
done
|
||||
fi
|
||||
|
||||
# check if wifi driver is bugged
|
||||
if ! check_brcm; then
|
||||
if ! reload_brcm; then
|
||||
echo "Could not reload wifi driver. Reboot"
|
||||
reboot
|
||||
fi
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
# start mon0
|
||||
start_monitor_interface
|
||||
|
||||
|
@@ -88,6 +88,27 @@ POST_RESPONSE = """
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
|
||||
function checkPwnagotchi() {
|
||||
var target = 'http://' + document.location.hostname + ':8080/';
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', target);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200 || xhr.status == 401) {
|
||||
window.location.replace(target);
|
||||
}else{
|
||||
setTimeout(checkPwnagotchi, 1000);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
setTimeout(checkPwnagotchi, 1000);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body style="margin:0;">
|
||||
|
||||
|
@@ -12,9 +12,28 @@ blink_led() {
|
||||
sleep 0.3
|
||||
}
|
||||
|
||||
# check if brcm is stuck
|
||||
check_brcm() {
|
||||
if [[ "$(journalctl -n10 -k --since -5m | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 5 ]]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# reload mod
|
||||
reload_brcm() {
|
||||
if ! modprobe -r brcmfmac; then
|
||||
return 1
|
||||
fi
|
||||
if ! modprobe brcmfmac; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# starts mon0
|
||||
start_monitor_interface() {
|
||||
iw phy phy0 interface add mon0 type monitor && ifconfig mon0 up
|
||||
iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add mon0 type monitor && ifconfig mon0 up
|
||||
}
|
||||
|
||||
# stops mon0
|
||||
@@ -158,7 +177,8 @@ EOF
|
||||
|
||||
pkill wpa_supplicant
|
||||
pkill dnsmasq
|
||||
kill "$(pgrep -f "decryption-webserver")"
|
||||
pid="$(pgrep -f "decryption-webserver")"
|
||||
[[ -n "$pid" ]] && kill "$pid"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@
|
||||
"name": "pwnagotchi",
|
||||
"type": "arm-image",
|
||||
"iso_url": "https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-07-12/2019-07-10-raspbian-buster-lite.zip",
|
||||
"iso_checksum_type": "sha256",
|
||||
"iso_checksum": "9e5cf24ce483bb96e7736ea75ca422e3560e7b455eee63dd28f66fa1825db70e",
|
||||
"last_partition_extra_size": 3221225472
|
||||
}
|
||||
|
@@ -35,10 +35,10 @@
|
||||
- ifup@wlan0.service
|
||||
packages:
|
||||
bettercap:
|
||||
url: "https://github.com/bettercap/bettercap/releases/download/v2.27.1/bettercap_linux_armhf_v2.27.1.zip"
|
||||
url: "https://github.com/bettercap/bettercap/releases/download/v2.31.0/bettercap_linux_armhf_v2.31.0.zip"
|
||||
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
|
||||
pwngrid:
|
||||
url: "https://github.com/evilsocket/pwngrid/releases/download/v1.10.1/pwngrid_linux_armhf_v1.10.1.zip"
|
||||
url: "https://github.com/evilsocket/pwngrid/releases/download/v1.10.3/pwngrid_linux_armhf_v1.10.3.zip"
|
||||
apt:
|
||||
hold:
|
||||
- firmware-atheros
|
||||
@@ -178,7 +178,7 @@
|
||||
chdir: /usr/local/src/gratis
|
||||
target: rpi
|
||||
params:
|
||||
EPD_IO: epd_io.h
|
||||
EPD_IO: epd_io_free_uart.h
|
||||
PANEL_VERSION: 'V231_G2'
|
||||
when: gratisgit.changed
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
chdir: /usr/local/src/gratis
|
||||
target: rpi-install
|
||||
params:
|
||||
EPD_IO: epd_io.h
|
||||
EPD_IO: epd_io_free_uart.h
|
||||
PANEL_VERSION: 'V231_G2'
|
||||
when: gratisgit.changed
|
||||
|
||||
@@ -243,13 +243,13 @@
|
||||
|
||||
- name: install opencv-python
|
||||
pip:
|
||||
name: "https://www.piwheels.hostedpi.com/simple/opencv-python/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl"
|
||||
name: "https://www.piwheels.org/simple/opencv-python/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl"
|
||||
extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
|
||||
when: (pip_packages['opencv-python'] is undefined) or (pip_packages['opencv-python'] != '3.4.3.18')
|
||||
|
||||
- name: install tensorflow
|
||||
pip:
|
||||
name: "https://www.piwheels.hostedpi.com/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv6l.whl"
|
||||
name: "https://www.piwheels.org/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv6l.whl"
|
||||
extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
|
||||
when: (pip_packages['tensorflow'] is undefined) or (pip_packages['tensorflow'] != '1.13.1')
|
||||
|
||||
|
@@ -106,12 +106,6 @@ def temperature(celsius=True):
|
||||
|
||||
|
||||
def shutdown():
|
||||
logging.warning("syncing...")
|
||||
|
||||
from pwnagotchi import fs
|
||||
for m in fs.mounts:
|
||||
m.sync()
|
||||
|
||||
logging.warning("shutting down ...")
|
||||
|
||||
from pwnagotchi.ui import view
|
||||
@@ -119,6 +113,13 @@ def shutdown():
|
||||
view.ROOT.on_shutdown()
|
||||
# give it some time to refresh the ui
|
||||
time.sleep(10)
|
||||
|
||||
logging.warning("syncing...")
|
||||
|
||||
from pwnagotchi import fs
|
||||
for m in fs.mounts:
|
||||
m.sync()
|
||||
|
||||
os.system("sync")
|
||||
os.system("halt")
|
||||
|
||||
@@ -153,5 +154,11 @@ def reboot(mode=None):
|
||||
elif mode == 'MANU':
|
||||
os.system("touch /root/.pwnagotchi-manual")
|
||||
|
||||
logging.warning("syncing...")
|
||||
|
||||
from pwnagotchi import fs
|
||||
for m in fs.mounts:
|
||||
m.sync()
|
||||
|
||||
os.system("sync")
|
||||
os.system("shutdown -r now")
|
||||
|
@@ -1 +1 @@
|
||||
__version__ = '1.5.2'
|
||||
__version__ = '1.5.4'
|
||||
|
@@ -307,7 +307,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
|
||||
def start_session_fetcher(self):
|
||||
_thread.start_new_thread(self._fetch_stats, ())
|
||||
_thread.start_new_thread(self._fetch_stats, ())
|
||||
|
||||
|
||||
def _fetch_stats(self):
|
||||
@@ -323,7 +323,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
||||
async def _on_event(self, msg):
|
||||
found_handshake = False
|
||||
jmsg = json.loads(msg)
|
||||
|
||||
|
||||
if jmsg['tag'] == 'wifi.client.handshake':
|
||||
filename = jmsg['data']['file']
|
||||
sta_mac = jmsg['data']['station']
|
||||
@@ -331,6 +331,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
||||
key = "%s -> %s" % (sta_mac, ap_mac)
|
||||
if key not in self._handshakes:
|
||||
self._handshakes[key] = jmsg
|
||||
s = self.session()
|
||||
ap_and_station = self._find_ap_sta_in(sta_mac, ap_mac, s)
|
||||
if ap_and_station is None:
|
||||
logging.warning("!!! captured new handshake: %s !!!", key)
|
||||
@@ -364,7 +365,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
def start_event_polling(self):
|
||||
# start a thread and pass in the mainloop
|
||||
_thread.start_new_thread(self._event_poller, (asyncio.new_event_loop(),))
|
||||
_thread.start_new_thread(self._event_poller, (asyncio.get_event_loop(),))
|
||||
|
||||
|
||||
def is_module_running(self, module):
|
||||
|
@@ -47,6 +47,8 @@ class Client(object):
|
||||
logging.debug("Error while parsing event (%s)", ex)
|
||||
except websockets.exceptions.ConnectionClosedError:
|
||||
logging.debug("Lost websocket connection. Reconnecting...")
|
||||
except websockets.exceptions.WebSocketException as wex:
|
||||
logging.debug("Websocket exception (%s)", wex)
|
||||
|
||||
def run(self, command, verbose_errors=True):
|
||||
r = requests.post("%s/session" % self.url, auth=self.auth, json={'cmd': command})
|
||||
|
@@ -2,6 +2,9 @@ main.name = ""
|
||||
main.lang = "en"
|
||||
main.confd = "/etc/pwnagotchi/conf.d/"
|
||||
main.custom_plugins = ""
|
||||
main.custom_plugin_repos = [
|
||||
"https://github.com/evilsocket/pwnagotchi-plugins-contrib/archive/master.zip"
|
||||
]
|
||||
main.iface = "mon0"
|
||||
main.mon_start_cmd = "/usr/bin/monstart"
|
||||
main.mon_stop_cmd = "/usr/bin/monstop"
|
||||
@@ -49,6 +52,7 @@ main.plugins.wpa-sec.whitelist = []
|
||||
main.plugins.wigle.enabled = false
|
||||
main.plugins.wigle.api_key = ""
|
||||
main.plugins.wigle.whitelist = []
|
||||
main.plugins.wigle.donate = true
|
||||
|
||||
main.plugins.bt-tether.enabled = false
|
||||
|
||||
@@ -110,6 +114,7 @@ main.plugins.led.patterns.peer_detected = "oo oo oo oo oo oo oo"
|
||||
main.plugins.led.patterns.peer_lost = "oo oo oo oo oo oo oo"
|
||||
|
||||
main.plugins.logtail.enabled = false
|
||||
main.plugins.logtail.max-lines = 10000
|
||||
|
||||
main.plugins.session-stats.enabled = true
|
||||
main.plugins.session-stats.save_directory = "/var/tmp/pwnagotchi/sessions/"
|
||||
@@ -179,6 +184,9 @@ ui.faces.angry = "(-_-')"
|
||||
ui.faces.friend = "(♥‿‿♥)"
|
||||
ui.faces.broken = "(☓‿‿☓)"
|
||||
ui.faces.debug = "(#__#)"
|
||||
ui.faces.upload = "(1__0)"
|
||||
ui.faces.upload1 = "(1__1)"
|
||||
ui.faces.upload2 = "(0__1)"
|
||||
|
||||
ui.web.enabled = true
|
||||
ui.web.address = "0.0.0.0"
|
||||
|
@@ -154,7 +154,7 @@ class MemoryFS:
|
||||
source, dest = (self.disk, self.mountpoint) if to_ram else (self.mountpoint, self.disk)
|
||||
needed, actually_free = size_of(source), shutil.disk_usage(dest)[2]
|
||||
if actually_free >= needed:
|
||||
logging.debug("[FS] Syning %s -> %s", source,dest)
|
||||
logging.debug("[FS] Syncing %s -> %s", source,dest)
|
||||
if self.rsync:
|
||||
os.system(f"rsync -aXv --inplace --no-whole-file --delete-after {source}/ {dest}/ >/dev/null 2>&1")
|
||||
else:
|
||||
|
BIN
pwnagotchi/locale/af/LC_MESSAGES/voice.mo
Normal file
BIN
pwnagotchi/locale/af/LC_MESSAGES/voice.mo
Normal file
Binary file not shown.
248
pwnagotchi/locale/af/LC_MESSAGES/voice.po
Normal file
248
pwnagotchi/locale/af/LC_MESSAGES/voice.po
Normal file
@@ -0,0 +1,248 @@
|
||||
# Afrikaans translation of pwnagotchi.
|
||||
# Copyright (C) 2020.
|
||||
# This file is distributed under the same license as the pwnagotchi package.
|
||||
# FIRST AUTHOR MatthewNunu https://github.com/MatthewNunu, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 1.5.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-11-29 21:50+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: MatthewNunu https://github.com/MatthewNunu\n"
|
||||
"Language-Team: \n"
|
||||
"Language: Afrikaans\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 "Hi, ek is Pwnagotchi! Aanvang ..."
|
||||
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Nuwe dag, nuwe jag, nuwe pwns!"
|
||||
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "Hack die wêreld!"
|
||||
|
||||
msgid "AI ready."
|
||||
msgstr "AI gereed."
|
||||
|
||||
msgid "The neural network is ready."
|
||||
msgstr "Die neurale netwerk is gereed."
|
||||
|
||||
msgid "Generating keys, do not turn off ..."
|
||||
msgstr "Genereer wagwoord, moenie afskakel nie ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Haai, kanaal {channel} is gratis! Jou AP sal dankie sê."
|
||||
|
||||
msgid "Reading last session logs ..."
|
||||
msgstr "Lees laaste sessie logs ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Read {lines_so_far} log lines so far ..."
|
||||
msgstr "Ek het {lines_so_far} tot dusver gelees ..."
|
||||
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Ek's verveeld ..."
|
||||
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Kom ons gaan vir 'n loopie!"
|
||||
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Dit is die beste dag van my lewe!"
|
||||
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Poes kak dag :/"
|
||||
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Ek's baie verveeld ..."
|
||||
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Ek's baie hartseer ..."
|
||||
|
||||
msgid "I'm sad"
|
||||
msgstr "Ek's hartseer ..."
|
||||
|
||||
msgid "Leave me alone ..."
|
||||
msgstr "Los my uit ..."
|
||||
|
||||
msgid "I'm mad at you!"
|
||||
msgstr "Ek is kwaad vir jou!"
|
||||
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Ek leef die lewe!"
|
||||
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Ek pwn daarom is ek."
|
||||
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Soveel netwerke!!!"
|
||||
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Ek het soveel pret!"
|
||||
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "My misdaad is dié van nuuskierigheid ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you."
|
||||
msgstr "Hallo {name}! Lekker om jou te ontmoet."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Yo {name}! Sup?"
|
||||
msgstr "Yo {name}! Sup?"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey {name} how are you doing?"
|
||||
msgstr "Haai {name} hoe doen jy?"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby!"
|
||||
msgstr "Eenheid {name}} is naby!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "Uhm ... totsiens {name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name} is weg ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Whoops ... {name} is weg."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "{name} gemis!"
|
||||
|
||||
msgid "Missed!"
|
||||
msgstr "Gemis!"
|
||||
|
||||
msgid "Good friends are a blessing!"
|
||||
msgstr "Goeie vriende is 'n seën!"
|
||||
|
||||
msgid "I love my friends!"
|
||||
msgstr "Ek is lief vir my vriende!"
|
||||
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Niemand wil met my speel nie ..."
|
||||
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Ek voel so alleen ..."
|
||||
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Waar is almal?!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Slaap vir {secs}s ..."
|
||||
|
||||
msgid "Zzzzz"
|
||||
msgstr "Zzzzz"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr "ZzzZzzz ({secs}s)"
|
||||
|
||||
msgid "Good night."
|
||||
msgstr "Goeie nag."
|
||||
|
||||
msgid "Zzz"
|
||||
msgstr "Zzz"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Wag tans vir {secs}s ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Rondkyk ({secs}s)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Haai {what} kom ons wees vriende!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Assosieer na {what}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr "Yo {what}!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Net besluit dat {mac} geen WiFi nodig het nie!"
|
||||
|
||||
#, 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 "Koel, ons het {num} nuwe handdruk gekry!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "You have {count} new message{plural}!"
|
||||
msgstr "Jy het {count} nuwe boodskap!"
|
||||
|
||||
msgid "Oops, something went wrong ... Rebooting ..."
|
||||
msgstr "Oops, iets het verkeerd gegaan ... Herlaai ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "Geskop {num} stasies\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "Gemaak {num} nuwe vriende\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "Het {num} handdrukke\n"
|
||||
|
||||
msgid "Met 1 peer"
|
||||
msgstr "Ontmoet 1 eweknie"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "Ontmoet {num} eweknie"
|
||||
|
||||
#, 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 ""
|
||||
"Ek was pwning vir {duration} en het {deauthed} kliënte geskop! Ek het ook ontmoet "
|
||||
"{associated} nuwe vriende en het {handshakes} handdrukke geëet! #pwnagotchi "
|
||||
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
msgstr "uur"
|
||||
|
||||
msgid "minutes"
|
||||
msgstr "minute"
|
||||
|
||||
msgid "seconds"
|
||||
msgstr "sekondes"
|
||||
|
||||
msgid "hour"
|
||||
msgstr "uur"
|
||||
|
||||
msgid "minute"
|
||||
msgstr "minuut"
|
||||
|
||||
msgid "second"
|
||||
msgstr "tweede"
|
Binary file not shown.
@@ -40,7 +40,7 @@ msgstr "创建密钥中, 请勿断电..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr ""
|
||||
msgstr "嘿,频道{channel}是免费的!你的AP会说谢谢。"
|
||||
|
||||
msgid "I'm bored ..."
|
||||
msgstr "我无聊了..."
|
||||
@@ -84,7 +84,7 @@ msgstr "你好{name}!很高兴认识你."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby!"
|
||||
msgstr ""
|
||||
msgstr "小队{name}就在附近!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
@@ -193,7 +193,7 @@ msgid "Got {num} handshakes\n"
|
||||
msgstr "捕获了{num}握手包\n"
|
||||
|
||||
msgid "Met 1 peer"
|
||||
msgstr ""
|
||||
msgstr "有{num}同龄人"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
|
Binary file not shown.
@@ -8,25 +8,26 @@ msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-09 17:42+0200\n"
|
||||
"PO-Revision-Date: 2019-10-09 21:07+0000\n"
|
||||
"Last-Translator: diegopastor <dpastor29@alumnos.uaq.mx>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: spanish\n"
|
||||
"PO-Revision-Date: 2020-08-25 23:06+0200\n"
|
||||
"Last-Translator: Sergio Ruiz <serginator@gmail.com>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language-Team: \n"
|
||||
"X-Generator: Poedit 2.4.1\n"
|
||||
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr "ZzzzZZzzzzZzzz"
|
||||
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr "Hola, soy Pwnagotchi! Empezando ..."
|
||||
msgstr "¡Hola, soy Pwnagotchi! Empezando ..."
|
||||
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Nuevo día, nueva cazería, nuevos pwns!"
|
||||
msgstr "Nuevo día, nueva caceria, nuevos pwns!"
|
||||
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "Hackea el planeta!"
|
||||
msgstr "¡Hackea el planeta!"
|
||||
|
||||
msgid "AI ready."
|
||||
msgstr "IA lista."
|
||||
@@ -36,51 +37,51 @@ msgstr "La red neuronal está lista."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Oye, el canal {channel} está libre! Tú AP lo agradecerá."
|
||||
msgstr "¡Oye, el canal {channel} está libre! Tu AP lo agradecerá."
|
||||
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Estoy aburrido ..."
|
||||
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Vamos por un paseo!"
|
||||
msgstr "¡Vamos por un paseo!"
|
||||
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Este es el mejor día de mi vida!"
|
||||
msgstr "¡Este es el mejor día de mi vida!"
|
||||
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Día de mierda :/"
|
||||
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Estoy extremadamente aburrido ..."
|
||||
msgstr "Estoy muy aburrido ..."
|
||||
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Estoy muy triste ..."
|
||||
|
||||
msgid "I'm sad"
|
||||
msgstr "Estoy triste."
|
||||
msgstr "Estoy triste"
|
||||
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Estoy viviendo la vida!"
|
||||
msgstr "¡Estoy viviendo la vida!"
|
||||
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Pwneo, por lo tanto, existo"
|
||||
msgstr "Pwneo, luego existo."
|
||||
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Cuantas redes!!!"
|
||||
msgstr "¡¡¡Cuántas redes!!!"
|
||||
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Me estoy divirtiendo mucho!"
|
||||
msgstr "¡Me estoy divirtiendo mucho!"
|
||||
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "Mi único crimen es la curiosidad ..."
|
||||
msgstr "Mi crimen es la curiosidad ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr "Hola {name}! encantado de conocerte."
|
||||
msgstr "¡Hola {name}! Encantado de conocerte. {name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr "La unidad {name} está cerca!"
|
||||
msgstr "¡La unidad {name} está cerca! {name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
@@ -92,14 +93,14 @@ msgstr "{name} se fue ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Uy ... {name} se fue"
|
||||
msgstr "Ups ... {name} se fue."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "{name} perdido!"
|
||||
msgstr "¡{name} perdido!"
|
||||
|
||||
msgid "Missed!"
|
||||
msgstr "Perdido!"
|
||||
msgstr "¡Perdido!"
|
||||
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Nadie quiere jugar conmigo ..."
|
||||
@@ -108,11 +109,11 @@ msgid "I feel so alone ..."
|
||||
msgstr "Me siento tan solo ..."
|
||||
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Dónde está todo el mundo?"
|
||||
msgstr "¡¿Dónde está todo el mundo?!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Tomándo una siesta por {secs}s ..."
|
||||
msgstr "Descansando durante {secs}s ..."
|
||||
|
||||
msgid "Zzzzz"
|
||||
msgstr "Zzzzz"
|
||||
@@ -133,23 +134,23 @@ msgstr "Esperando {secs}s .."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Mirando al rededor ({secs}s)"
|
||||
msgstr "Mirando alrededor ({secs}s)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Oye {what} seamos amigos!"
|
||||
msgstr "¡Oye {what} seamos amigos!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Asociando a {what}"
|
||||
msgstr "Asociándome a {what}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr "Ey {what}!"
|
||||
msgstr "¡Ey {what}!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Acabo de decidir que {mac} no necesita WiFi!"
|
||||
msgstr "¡Acabo de decidir que {mac} no necesita WiFi!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
@@ -157,14 +158,14 @@ msgstr "Desautenticando a {mac}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "Expulsando y banneando a {mac}!"
|
||||
msgstr "¡Expulsando y baneando a {mac}!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Genial, obtuvimos {num} nuevo{plural} handshake{plural}!"
|
||||
msgstr "¡Genial, obtuvimos {num} nuevo{plural} handshake{plural}!"
|
||||
|
||||
msgid "Oops, something went wrong ... Rebooting ..."
|
||||
msgstr "Oops, algo salió mal ... Reiniciándo ..."
|
||||
msgstr "Oops, algo salió mal ... Reiniciando ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
@@ -172,27 +173,27 @@ msgstr "Expulsamos {num} estaciones\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "Hicimos {num} nuevos amigos\n"
|
||||
msgstr "Hice {num} nuevos amigos\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "Obtuvimos {num} handshakes\n"
|
||||
msgstr "Consegui {num} handshakes\n"
|
||||
|
||||
msgid "Met 1 peer"
|
||||
msgstr "Conocí 1 igual"
|
||||
msgstr "Conocí 1 colega"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "Conocí {num} iguales"
|
||||
msgstr "Conocí {num} colegas"
|
||||
|
||||
#, 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"
|
||||
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi #pwnlog "
|
||||
"#pwnlife #hacktheplanet #skynet"
|
||||
msgstr ""
|
||||
"He estado pwneando por {duration} y expulsé {deauthed} clientes! También conocí"
|
||||
"{associated} nuevos amigos y me comí {handshakes} handshakes! #pwnagotchi "
|
||||
"¡He estado pwneando por {duration} y expulsé {deauthed} clientes! También "
|
||||
"conocí {associated} nuevos amigos y comí {handshakes} handshakes! #pwnagotchi "
|
||||
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
|
Binary file not shown.
@@ -20,7 +20,7 @@ msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr "ZzzzZZzzzzZzzz"
|
||||
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr "Hoi, Ik ben Pwnagotchi! Opstarten ..."
|
||||
msgstr "Hoi, Ik ben Pwnagotchi! Aan het opstarten ..."
|
||||
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Nieuwe dag, nieuwe jacht, nieuwe pwns!"
|
||||
@@ -32,7 +32,7 @@ msgid "AI ready."
|
||||
msgstr "AI is klaar."
|
||||
|
||||
msgid "The neural network is ready."
|
||||
msgstr "Neuronen netwerkis klaar voor gebruik."
|
||||
msgstr "Neuronen netwerk is klaar."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
@@ -42,37 +42,37 @@ msgid "I'm bored ..."
|
||||
msgstr "Ik verveel me ..."
|
||||
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Laten we een rondje lopen!"
|
||||
msgstr "Laten we gaan wandelen!"
|
||||
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Dit is de beste dag van mijn leven!"
|
||||
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Ruk dag :/"
|
||||
msgstr "Wat een rotdag :/"
|
||||
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Ik verveel me kapot ..."
|
||||
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Ik ben ergverdrietig ..."
|
||||
msgstr "Ik ben erg verdrietig ..."
|
||||
|
||||
msgid "I'm sad"
|
||||
msgstr "Ik ben verdrietig"
|
||||
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Beter kan het levenniet worden!"
|
||||
msgstr "Beter kan het leven niet worden!"
|
||||
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Ik pwn daarom besta ik."
|
||||
msgstr "Ik pwn daarom ben ik er."
|
||||
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Zo veel netwerken!!!"
|
||||
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Dit is zo leuk!"
|
||||
msgstr "Ik heb zoveel plezier!"
|
||||
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "Mijn enige misdrijf is mijn nieuwsgierigheid ..."
|
||||
msgstr "Mijn misdrijf is mijn nieuwsgierigheid ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
@@ -88,11 +88,11 @@ msgstr "Uhm ...tot ziens {name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name} is weg"
|
||||
msgstr "{name} is weg ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Whoopsie ...{name} is weg"
|
||||
msgstr "Whoopsie ...{name} is weg."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
@@ -102,10 +102,10 @@ msgid "Missed!"
|
||||
msgstr "Gemist!"
|
||||
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Niemand wil metmij spelen ..."
|
||||
msgstr "Niemand wil met mij spelen ..."
|
||||
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Zo alleen ..."
|
||||
msgstr "Ik voel me zo alleen ..."
|
||||
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Waar is iedereen?!"
|
||||
@@ -119,11 +119,11 @@ msgstr "Zzzzz"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
msgstr "ZzzZzzz ({secs}s)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Even {secs}s wachten ..."
|
||||
msgstr "Ik wacht voor {secs}s ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
@@ -131,7 +131,7 @@ msgstr "Rond kijken ({secs}s)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Hey {what}, laten we vriendenworden!"
|
||||
msgstr "Hey {what}, laten we vrienden worden!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
@@ -139,26 +139,26 @@ msgstr "Verbinden met {what}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr ""
|
||||
msgstr "Yo {what}!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Ik vind dat {mac} genoeg WiFiheeft gehad!"
|
||||
msgstr "Ik besloot dat {mac} geen WiFi meer nodig heeft!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr "De-autoriseren {mac}"
|
||||
msgstr "Deauthenticatie van {mac}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "Ik ga {mac} even kicken!"
|
||||
msgstr "Kickbanning {mac}!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Gaaf, we hebben {num} nieuwe handshake{plural}!"
|
||||
msgstr "Cool, we hebben {num} nieuwe handshake{plural}!"
|
||||
|
||||
msgid "Oops, something went wrong ... Rebooting ..."
|
||||
msgstr "Oops, iets ging fout ...Rebooting ..."
|
||||
msgstr "Oops, er ging iets fout ...Rebooting ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
@@ -166,11 +166,11 @@ msgstr "{num} stations gekicked\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "{num} nieuwe vrienden\n"
|
||||
msgstr "{num} nieuwe vrienden gemaakt.\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "{num} nieuwe handshakes\n"
|
||||
msgstr "Ik heb {num} nieuwe handshakes\n"
|
||||
|
||||
msgid "Met 1 peer"
|
||||
msgstr "1 peer ontmoet"
|
||||
@@ -190,19 +190,19 @@ msgstr ""
|
||||
"gegeten! #pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
msgstr ""
|
||||
msgstr "uren"
|
||||
|
||||
msgid "minutes"
|
||||
msgstr ""
|
||||
msgstr "minuten"
|
||||
|
||||
msgid "seconds"
|
||||
msgstr ""
|
||||
msgstr "seconden"
|
||||
|
||||
msgid "hour"
|
||||
msgstr ""
|
||||
msgstr "uur"
|
||||
|
||||
msgid "minute"
|
||||
msgstr ""
|
||||
msgstr "minuut"
|
||||
|
||||
msgid "second"
|
||||
msgstr ""
|
||||
msgstr "seconde"
|
||||
|
BIN
pwnagotchi/locale/tw/LC_MESSAGES/voice.mo
Normal file
BIN
pwnagotchi/locale/tw/LC_MESSAGES/voice.mo
Normal file
Binary file not shown.
227
pwnagotchi/locale/tw/LC_MESSAGES/voice.po
Normal file
227
pwnagotchi/locale/tw/LC_MESSAGES/voice.po
Normal file
@@ -0,0 +1,227 @@
|
||||
# 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 <shark_shaking@hotmail.com>, 2020.
|
||||
# 有很多翻譯不到味,如果有繁體愛好者,歡迎之後大家一起翻譯!
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-10-21 15:56+0200\n"
|
||||
"PO-Revision-Date: 2020-10-22 10:00+0008\n"
|
||||
"Last-Translator: ShaqKSmith <shark_shaking@hotmail.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: traditional chinese\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 "HI!我是Pwnagotchi!\n程式啟動..."
|
||||
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "新的一天!\n新的狩獵!新的入侵!"
|
||||
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "我要駭入\n地球的所有人!"
|
||||
|
||||
msgid "AI ready."
|
||||
msgstr "人工智慧已啟動."
|
||||
|
||||
msgid "The neural network is ready."
|
||||
msgstr "神經網路已啟動."
|
||||
|
||||
msgid "Generating keys, do not turn off ..."
|
||||
msgstr "產生金鑰中,\n請勿關閉..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "嘿,{channel}很順暢!\n你的WIFI會感謝你的."
|
||||
|
||||
msgid "I'm bored ..."
|
||||
msgstr "我好無聊..."
|
||||
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "我們出去走走吧!"
|
||||
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "這是我生命中最美好的一天!"
|
||||
|
||||
msgid "Shitty day :/"
|
||||
msgstr "糟糕的一天 :/"
|
||||
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "我超無聊的..."
|
||||
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "我好難過..."
|
||||
|
||||
msgid "I'm sad"
|
||||
msgstr "傷心。"
|
||||
|
||||
msgid "I'm living the life!"
|
||||
msgstr "真是充實的一生!"
|
||||
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "我駭故我在."
|
||||
|
||||
msgid "So many networks!!!"
|
||||
msgstr "好多網路啊!!!"
|
||||
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "我玩的超級開心!"
|
||||
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "我的缺點就是\n太好奇了..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you."
|
||||
msgstr "Hello{name}!\n很高興認識你."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby!"
|
||||
msgstr "{name}\n就在附近!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "啊 ... \n拜拜{name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name}\n不見了 ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "歐哦...\n{name}\n不見了."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "我剛剛錯過了{name}!"
|
||||
|
||||
msgid "Missed!"
|
||||
msgstr "又錯過了!"
|
||||
|
||||
msgid "Good friends are a blessing!"
|
||||
msgstr "有個好朋友\n真幸福!"
|
||||
|
||||
msgid "I love my friends!"
|
||||
msgstr "我喜歡\n我的朋友!"
|
||||
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "沒人想跟我玩..."
|
||||
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "我感覺好孤單..."
|
||||
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "大家都去哪裡了?!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "我想瞇{secs}秒一下..."
|
||||
|
||||
msgid "Zzzzz"
|
||||
msgstr "Zzzzz"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr "ZzzZzzz({secs}秒)"
|
||||
|
||||
msgid "Good night."
|
||||
msgstr "晚安."
|
||||
|
||||
msgid "Zzz"
|
||||
msgstr "Zzz"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "等我{secs}秒..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "環顧四周({secs}秒)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "嗨\n{what}\n讓我我們來當朋友吧!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "正在連接\n{what}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr "喲,\n{what}!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "我要讓\n{mac}\n斷線!\n他不需要上網!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr "解除\n{mac}\n的授權中"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "把\n{mac}\n踢出中!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "酷哦,我們抓到{num}個\n新的握手包{plural}!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "You have {count} new message{plural}!"
|
||||
msgstr "你有{count}個新訊息{plural}!"
|
||||
|
||||
msgid "Oops, something went wrong ... Rebooting ..."
|
||||
msgstr "喔歐,有些地方出錯了...\n重新啟動中..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "踢了 {num} 個設備\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "交了 {num} 個新朋友\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "捕獲了 {num} 個握手包\n"
|
||||
|
||||
msgid "Met 1 peer 同好"
|
||||
msgstr "遇到了 1 個"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "遇到了 {num} 個同好"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
|
||||
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
|
||||
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
msgstr "我花了{duration}的時間\n駭入和踢了{deauthed}好多設備.\n"
|
||||
"我還交了好多{associated}新朋友,\n而且抓到了{handshakes}握手包!"
|
||||
"#pwnagotchi#入侵日志 #駭客人生 #入侵整個星球 #天網"
|
||||
|
||||
msgid "hours"
|
||||
msgstr "時"
|
||||
|
||||
msgid "minutes"
|
||||
msgstr "分"
|
||||
|
||||
msgid "seconds"
|
||||
msgstr "秒"
|
||||
|
||||
msgid "hour"
|
||||
msgstr "時"
|
||||
|
||||
msgid "minute"
|
||||
msgstr "分"
|
||||
|
||||
msgid "second"
|
||||
msgstr "秒"
|
@@ -244,3 +244,7 @@ msgstr ""
|
||||
|
||||
msgid "second"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Uploading data to {to} ..."
|
||||
msgstr ""
|
||||
|
@@ -58,6 +58,8 @@ def toggle_plugin(name, enable=True):
|
||||
|
||||
if enable and name in database and name not in loaded:
|
||||
load_from_file(database[name])
|
||||
if name in loaded and pwnagotchi.config and name in pwnagotchi.config['main']['plugins']:
|
||||
loaded[name].options = pwnagotchi.config['main']['plugins'][name]
|
||||
one(name, 'loaded')
|
||||
if pwnagotchi.config:
|
||||
one(name, 'config_changed', pwnagotchi.config)
|
||||
|
@@ -1,6 +1,5 @@
|
||||
# Handles the commandline stuff
|
||||
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
import glob
|
||||
@@ -11,7 +10,6 @@ from pwnagotchi.utils import download_file, unzip, save_config, parse_version, m
|
||||
from pwnagotchi.plugins import default_path
|
||||
|
||||
|
||||
REPO_URL = 'https://github.com/evilsocket/pwnagotchi-plugins-contrib/archive/master.zip'
|
||||
SAVE_DIR = '/usr/local/share/pwnagotchi/availaible-plugins/'
|
||||
DEFAULT_INSTALL_PATH = '/usr/local/share/pwnagotchi/installed-plugins/'
|
||||
|
||||
@@ -75,7 +73,7 @@ def handle_cmd(args, config):
|
||||
Parses the arguments and does the thing the user wants
|
||||
"""
|
||||
if args.plugincmd == 'update':
|
||||
return update()
|
||||
return update(config)
|
||||
elif args.plugincmd == 'search':
|
||||
args.installed = True # also search in installed plugins
|
||||
return list_plugins(args, config, args.pattern)
|
||||
@@ -349,41 +347,48 @@ def _analyse_dir(path):
|
||||
return results
|
||||
|
||||
|
||||
def update():
|
||||
def update(config):
|
||||
"""
|
||||
Updates the database
|
||||
"""
|
||||
global REPO_URL, SAVE_DIR
|
||||
global SAVE_DIR
|
||||
|
||||
DEST = os.path.join(SAVE_DIR, 'plugins.zip')
|
||||
logging.info('Downloading plugins to %s', DEST)
|
||||
|
||||
try:
|
||||
os.makedirs(SAVE_DIR, exist_ok=True)
|
||||
before_update = _analyse_dir(SAVE_DIR)
|
||||
|
||||
download_file(REPO_URL, os.path.join(SAVE_DIR, DEST))
|
||||
|
||||
logging.info('Unzipping...')
|
||||
unzip(DEST, SAVE_DIR, strip_dirs=1)
|
||||
|
||||
after_update = _analyse_dir(SAVE_DIR)
|
||||
|
||||
b_len = len(before_update)
|
||||
a_len = len(after_update)
|
||||
|
||||
if a_len > b_len:
|
||||
logging.info('Found %d new file(s).', a_len - b_len)
|
||||
|
||||
changed = 0
|
||||
for filename, filehash in after_update.items():
|
||||
if filename in before_update and filehash != before_update[filename]:
|
||||
changed += 1
|
||||
|
||||
if changed:
|
||||
logging.info('%d file(s) were changed.', changed)
|
||||
|
||||
return 0
|
||||
except Exception as ex:
|
||||
logging.error('Error while updating plugins %s', ex)
|
||||
urls = config['main']['custom_plugin_repos']
|
||||
if not urls:
|
||||
logging.info('No plugin repositories configured.')
|
||||
return 1
|
||||
|
||||
rc = 0
|
||||
for idx, REPO_URL in enumerate(urls):
|
||||
DEST = os.path.join(SAVE_DIR, 'plugins%d.zip' % idx)
|
||||
logging.info('Downloading plugins from %s to %s', REPO_URL, DEST)
|
||||
|
||||
try:
|
||||
os.makedirs(SAVE_DIR, exist_ok=True)
|
||||
before_update = _analyse_dir(SAVE_DIR)
|
||||
|
||||
download_file(REPO_URL, os.path.join(SAVE_DIR, DEST))
|
||||
|
||||
logging.info('Unzipping...')
|
||||
unzip(DEST, SAVE_DIR, strip_dirs=1)
|
||||
|
||||
after_update = _analyse_dir(SAVE_DIR)
|
||||
|
||||
b_len = len(before_update)
|
||||
a_len = len(after_update)
|
||||
|
||||
if a_len > b_len:
|
||||
logging.info('Found %d new file(s).', a_len - b_len)
|
||||
|
||||
changed = 0
|
||||
for filename, filehash in after_update.items():
|
||||
if filename in before_update and filehash != before_update[filename]:
|
||||
changed += 1
|
||||
|
||||
if changed:
|
||||
logging.info('%d file(s) were changed.', changed)
|
||||
|
||||
except Exception as ex:
|
||||
logging.error('Error while updating plugins: %s', ex)
|
||||
rc = 1
|
||||
return rc
|
||||
|
@@ -419,15 +419,19 @@ class Device:
|
||||
|
||||
class BTTether(plugins.Plugin):
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '1.0.0'
|
||||
__version__ = '1.1.0'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This makes the display reachable over bluetooth'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.ready = False
|
||||
self.options = dict()
|
||||
self.devices = dict()
|
||||
self.lock = Lock()
|
||||
self.running = True
|
||||
self.status = '-'
|
||||
|
||||
|
||||
def on_loaded(self):
|
||||
# new config
|
||||
@@ -449,7 +453,7 @@ class BTTether(plugins.Plugin):
|
||||
if 'mac' in self.options:
|
||||
for opt in ['share_internet', 'mac', 'ip', 'netmask', 'interval']:
|
||||
if opt not in self.options or self.options[opt] is None:
|
||||
logging.error("BT-TETHER: Please specify the %s in your config.yml.", opt)
|
||||
logging.error("BT-TETHER: Please specify the %s in your config.toml.", opt)
|
||||
return
|
||||
|
||||
self.devices['legacy'] = Device(name='legacy', **self.options)
|
||||
@@ -466,22 +470,10 @@ class BTTether(plugins.Plugin):
|
||||
return
|
||||
|
||||
logging.info("BT-TETHER: Successfully loaded ...")
|
||||
self.ready = True
|
||||
|
||||
def on_unload(self, ui):
|
||||
with ui._lock:
|
||||
ui.remove_element('bluetooth')
|
||||
while self.running:
|
||||
time.sleep(1)
|
||||
|
||||
def on_ui_setup(self, ui):
|
||||
with ui._lock:
|
||||
ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-', position=(ui.width() / 2 - 15, 0),
|
||||
label_font=fonts.Bold, text_font=fonts.Medium))
|
||||
|
||||
def on_ui_update(self, ui):
|
||||
if not self.ready:
|
||||
return
|
||||
|
||||
with self.lock:
|
||||
devices_to_try = list()
|
||||
connected_priorities = list()
|
||||
any_device_connected = False # if this is true, last status on screen should be C
|
||||
@@ -508,11 +500,11 @@ class BTTether(plugins.Plugin):
|
||||
dev_remote = bt.wait_for_device(timeout=device.scantime)
|
||||
if dev_remote is None:
|
||||
logging.debug('BT-TETHER: Could not find %s, try again in %d minutes.', device.name, device.interval)
|
||||
ui.set('bluetooth', 'NF')
|
||||
self.status = 'NF'
|
||||
continue
|
||||
except Exception as bt_ex:
|
||||
logging.error(bt_ex)
|
||||
ui.set('bluetooth', 'NF')
|
||||
self.status = 'NF'
|
||||
continue
|
||||
|
||||
paired = bt.is_paired()
|
||||
@@ -521,7 +513,7 @@ class BTTether(plugins.Plugin):
|
||||
logging.debug('BT-TETHER: Paired with %s.', device.name)
|
||||
else:
|
||||
logging.debug('BT-TETHER: Pairing with %s failed ...', device.name)
|
||||
ui.set('bluetooth', 'PE')
|
||||
self.status = 'PE'
|
||||
continue
|
||||
else:
|
||||
logging.debug('BT-TETHER: Already paired.')
|
||||
@@ -539,17 +531,17 @@ class BTTether(plugins.Plugin):
|
||||
continue
|
||||
|
||||
if interface is None:
|
||||
ui.set('bluetooth', 'BE')
|
||||
self.status = 'BE'
|
||||
logging.debug('BT-TETHER: Could not establish nap connection with %s', device.name)
|
||||
continue
|
||||
|
||||
logging.debug('BT-TETHER: Created interface (%s)', interface)
|
||||
ui.set('bluetooth', 'C')
|
||||
self.status = 'C'
|
||||
any_device_connected = True
|
||||
device.tries = 0 # reset tries
|
||||
else:
|
||||
logging.debug('BT-TETHER: Could not establish nap connection with %s', device.name)
|
||||
ui.set('bluetooth', 'NF')
|
||||
self.status = 'NF'
|
||||
continue
|
||||
|
||||
addr = f"{device.ip}/{device.netmask}"
|
||||
@@ -561,7 +553,7 @@ class BTTether(plugins.Plugin):
|
||||
wrapped_interface = IfaceWrapper(interface)
|
||||
logging.debug('BT-TETHER: Add ip to %s', interface)
|
||||
if not wrapped_interface.set_addr(addr):
|
||||
ui.set('bluetooth', 'AE')
|
||||
self.status = 'AE'
|
||||
logging.debug("BT-TETHER: Could not add ip to %s", interface)
|
||||
continue
|
||||
|
||||
@@ -580,4 +572,20 @@ class BTTether(plugins.Plugin):
|
||||
resolv.write(nameserver + 'nameserver 9.9.9.9\n')
|
||||
|
||||
if any_device_connected:
|
||||
ui.set('bluetooth', 'C')
|
||||
self.status = 'C'
|
||||
|
||||
|
||||
def on_unload(self, ui):
|
||||
self.running = False
|
||||
with ui._lock:
|
||||
ui.remove_element('bluetooth')
|
||||
|
||||
|
||||
def on_ui_setup(self, ui):
|
||||
with ui._lock:
|
||||
ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-', position=(ui.width() / 2 - 15, 0),
|
||||
label_font=fonts.Bold, text_font=fonts.Medium))
|
||||
|
||||
|
||||
def on_ui_update(self, ui):
|
||||
ui.set('bluetooth', self.status)
|
||||
|
@@ -10,10 +10,13 @@ from pwnagotchi.ui.view import BLACK
|
||||
|
||||
class GPS(plugins.Plugin):
|
||||
__author__ = "evilsocket@gmail.com"
|
||||
__version__ = "1.0.0"
|
||||
__version__ = "1.0.1"
|
||||
__license__ = "GPL3"
|
||||
__description__ = "Save GPS coordinates whenever an handshake is captured."
|
||||
|
||||
LINE_SPACING = 10
|
||||
LABEL_SPACING = 0
|
||||
|
||||
def __init__(self):
|
||||
self.running = False
|
||||
self.coordinates = None
|
||||
@@ -55,31 +58,52 @@ class GPS(plugins.Plugin):
|
||||
logging.info("not saving GPS. Couldn't find location.")
|
||||
|
||||
def on_ui_setup(self, ui):
|
||||
# add coordinates for other displays
|
||||
if ui.is_waveshare_v2():
|
||||
lat_pos = (127, 75)
|
||||
lon_pos = (122, 84)
|
||||
alt_pos = (127, 94)
|
||||
elif ui.is_waveshare_v1():
|
||||
lat_pos = (130, 70)
|
||||
lon_pos = (125, 80)
|
||||
alt_pos = (130, 90)
|
||||
elif ui.is_inky():
|
||||
lat_pos = (127, 60)
|
||||
lon_pos = (127, 70)
|
||||
alt_pos = (127, 80)
|
||||
elif ui.is_waveshare144lcd():
|
||||
# guessed values, add tested ones if you can
|
||||
lat_pos = (67, 73)
|
||||
lon_pos = (62, 83)
|
||||
alt_pos = (67, 93)
|
||||
else:
|
||||
# guessed values, add tested ones if you can
|
||||
lat_pos = (127, 51)
|
||||
lon_pos = (127, 56)
|
||||
alt_pos = (102, 71)
|
||||
try:
|
||||
# Configure line_spacing
|
||||
line_spacing = int(self.options['linespacing'])
|
||||
except Exception:
|
||||
# Set default value
|
||||
line_spacing = self.LINE_SPACING
|
||||
|
||||
label_spacing = 0
|
||||
try:
|
||||
# Configure position
|
||||
pos = self.options['position'].split(',')
|
||||
pos = [int(x.strip()) for x in pos]
|
||||
lat_pos = (pos[0] + 5, pos[1])
|
||||
lon_pos = (pos[0], pos[1] + line_spacing)
|
||||
alt_pos = (pos[0] + 5, pos[1] + (2 * line_spacing))
|
||||
except Exception:
|
||||
# Set default value based on display type
|
||||
if ui.is_waveshare_v2():
|
||||
lat_pos = (127, 74)
|
||||
lon_pos = (122, 84)
|
||||
alt_pos = (127, 94)
|
||||
elif ui.is_waveshare_v1():
|
||||
lat_pos = (130, 70)
|
||||
lon_pos = (125, 80)
|
||||
alt_pos = (130, 90)
|
||||
elif ui.is_inky():
|
||||
lat_pos = (127, 60)
|
||||
lon_pos = (122, 70)
|
||||
alt_pos = (127, 80)
|
||||
elif ui.is_waveshare144lcd():
|
||||
# guessed values, add tested ones if you can
|
||||
lat_pos = (67, 73)
|
||||
lon_pos = (62, 83)
|
||||
alt_pos = (67, 93)
|
||||
elif ui.is_dfrobot_v2():
|
||||
lat_pos = (127, 74)
|
||||
lon_pos = (122, 84)
|
||||
alt_pos = (127, 94)
|
||||
elif ui.is_waveshare27inch():
|
||||
lat_pos = (6, 120)
|
||||
lon_pos = (1, 135)
|
||||
alt_pos = (6, 150)
|
||||
else:
|
||||
# guessed values, add tested ones if you can
|
||||
lat_pos = (127, 51)
|
||||
lon_pos = (122, 61)
|
||||
alt_pos = (127, 71)
|
||||
|
||||
ui.add_element(
|
||||
"latitude",
|
||||
@@ -90,7 +114,7 @@ class GPS(plugins.Plugin):
|
||||
position=lat_pos,
|
||||
label_font=fonts.Small,
|
||||
text_font=fonts.Small,
|
||||
label_spacing=label_spacing,
|
||||
label_spacing=self.LABEL_SPACING,
|
||||
),
|
||||
)
|
||||
ui.add_element(
|
||||
@@ -102,7 +126,7 @@ class GPS(plugins.Plugin):
|
||||
position=lon_pos,
|
||||
label_font=fonts.Small,
|
||||
text_font=fonts.Small,
|
||||
label_spacing=label_spacing,
|
||||
label_spacing=self.LABEL_SPACING,
|
||||
),
|
||||
)
|
||||
ui.add_element(
|
||||
@@ -114,11 +138,10 @@ class GPS(plugins.Plugin):
|
||||
position=alt_pos,
|
||||
label_font=fonts.Small,
|
||||
text_font=fonts.Small,
|
||||
label_spacing=label_spacing,
|
||||
label_spacing=self.LABEL_SPACING,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def on_unload(self, ui):
|
||||
with ui._lock:
|
||||
ui.remove_element('latitude')
|
||||
@@ -133,5 +156,5 @@ class GPS(plugins.Plugin):
|
||||
# last char is sometimes not completely drawn ¯\_(ツ)_/¯
|
||||
# using an ending-whitespace as workaround on each line
|
||||
ui.set("latitude", f"{self.coordinates['Latitude']:.4f} ")
|
||||
ui.set("longitude", f" {self.coordinates['Longitude']:.4f} ")
|
||||
ui.set("altitude", f" {self.coordinates['Altitude']:.1f}m ")
|
||||
ui.set("longitude", f"{self.coordinates['Longitude']:.4f} ")
|
||||
ui.set("altitude", f"{self.coordinates['Altitude']:.1f}m ")
|
||||
|
@@ -207,7 +207,6 @@ TEMPLATE = """
|
||||
}
|
||||
document.body.style.cursor = 'default';
|
||||
}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -254,6 +253,7 @@ class Logtail(plugins.Plugin):
|
||||
"""
|
||||
logging.info("Logtail plugin loaded.")
|
||||
|
||||
|
||||
def on_webhook(self, path, request):
|
||||
if not self.ready:
|
||||
return "Plugin not ready"
|
||||
@@ -264,10 +264,7 @@ class Logtail(plugins.Plugin):
|
||||
if path == 'stream':
|
||||
def generate():
|
||||
with open(self.config['main']['log']['path']) as f:
|
||||
# https://stackoverflow.com/questions/39549426/read-multiple-lines-from-a-file-batch-by-batch/39549901#39549901
|
||||
n = 1024
|
||||
for n_lines in iter(lambda: ''.join(islice(f, n)), ''):
|
||||
yield n_lines
|
||||
yield ''.join(f.readlines()[-self.options.get('max-lines', 4096):])
|
||||
while True:
|
||||
yield f.readline()
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# memtemp shows memory infos and cpu temperature
|
||||
#
|
||||
# mem usage, cpu load, cpu temp
|
||||
# mem usage, cpu load, cpu temp, cpu frequency
|
||||
#
|
||||
###############################################################
|
||||
#
|
||||
@@ -16,8 +16,15 @@
|
||||
# - Added CPU load
|
||||
# - Added horizontal and vertical orientation
|
||||
#
|
||||
# 19-09-2020 by crahan <crahan@n00.be>
|
||||
# - Added CPU frequency
|
||||
# - Made field types and order configurable (max 3 fields)
|
||||
# - Made line spacing and position configurable
|
||||
# - Updated code to dynamically generate UI elements
|
||||
# - Changed horizontal UI elements to Text
|
||||
# - Updated to version 1.0.2
|
||||
###############################################################
|
||||
from pwnagotchi.ui.components import LabeledValue
|
||||
from pwnagotchi.ui.components import LabeledValue, Text
|
||||
from pwnagotchi.ui.view import BLACK
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
import pwnagotchi.plugins as plugins
|
||||
@@ -27,54 +34,31 @@ import logging
|
||||
|
||||
class MemTemp(plugins.Plugin):
|
||||
__author__ = 'https://github.com/xenDE'
|
||||
__version__ = '1.0.1'
|
||||
__version__ = '1.0.2'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'A plugin that will display memory/cpu usage and temperature'
|
||||
|
||||
ALLOWED_FIELDS = {
|
||||
'mem': 'mem_usage',
|
||||
'cpu': 'cpu_load',
|
||||
'temp': 'cpu_temp',
|
||||
'freq': 'cpu_freq'
|
||||
}
|
||||
DEFAULT_FIELDS = ['mem', 'cpu', 'temp']
|
||||
LINE_SPACING = 10
|
||||
LABEL_SPACING = 0
|
||||
FIELD_WIDTH = 4
|
||||
|
||||
def on_loaded(self):
|
||||
logging.info("memtemp plugin loaded.")
|
||||
|
||||
def mem_usage(self):
|
||||
return int(pwnagotchi.mem_usage() * 100)
|
||||
return f"{int(pwnagotchi.mem_usage() * 100)}%"
|
||||
|
||||
def cpu_load(self):
|
||||
return int(pwnagotchi.cpu_load() * 100)
|
||||
return f"{int(pwnagotchi.cpu_load() * 100)}%"
|
||||
|
||||
def on_ui_setup(self, ui):
|
||||
if ui.is_waveshare_v2():
|
||||
h_pos = (180, 80)
|
||||
v_pos = (180, 61)
|
||||
elif ui.is_waveshare_v1():
|
||||
h_pos = (170, 80)
|
||||
v_pos = (170, 61)
|
||||
elif ui.is_waveshare144lcd():
|
||||
h_pos = (53, 77)
|
||||
v_pos = (78, 67)
|
||||
elif ui.is_inky():
|
||||
h_pos = (140, 68)
|
||||
v_pos = (165, 54)
|
||||
elif ui.is_waveshare27inch():
|
||||
h_pos = (192, 138)
|
||||
v_pos = (216, 122)
|
||||
else:
|
||||
h_pos = (155, 76)
|
||||
v_pos = (180, 61)
|
||||
|
||||
if self.options['orientation'] == "vertical":
|
||||
ui.add_element('memtemp', LabeledValue(color=BLACK, label='', value=' mem:-\n cpu:-\ntemp:-',
|
||||
position=v_pos,
|
||||
label_font=fonts.Small, text_font=fonts.Small))
|
||||
else:
|
||||
# default to horizontal
|
||||
ui.add_element('memtemp', LabeledValue(color=BLACK, label='', value='mem cpu temp\n - - -',
|
||||
position=h_pos,
|
||||
label_font=fonts.Small, text_font=fonts.Small))
|
||||
|
||||
def on_unload(self, ui):
|
||||
with ui._lock:
|
||||
ui.remove_element('memtemp')
|
||||
|
||||
def on_ui_update(self, ui):
|
||||
def cpu_temp(self):
|
||||
if self.options['scale'] == "fahrenheit":
|
||||
temp = (pwnagotchi.temperature() * 9 / 5) + 32
|
||||
symbol = "f"
|
||||
@@ -85,11 +69,116 @@ class MemTemp(plugins.Plugin):
|
||||
# default to celsius
|
||||
temp = pwnagotchi.temperature()
|
||||
symbol = "c"
|
||||
return f"{temp}{symbol}"
|
||||
|
||||
def cpu_freq(self):
|
||||
with open('/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq', 'rt') as fp:
|
||||
return f"{round(float(fp.readline())/1000000, 1)}G"
|
||||
|
||||
def pad_text(self, data):
|
||||
return " " * (self.FIELD_WIDTH - len(data)) + data
|
||||
|
||||
def on_ui_setup(self, ui):
|
||||
try:
|
||||
# Configure field list
|
||||
self.fields = self.options['fields'].split(',')
|
||||
self.fields = [x.strip() for x in self.fields if x.strip() in self.ALLOWED_FIELDS.keys()]
|
||||
self.fields = self.fields[:3] # limit to the first 3 fields
|
||||
except Exception:
|
||||
# Set default value
|
||||
self.fields = self.DEFAULT_FIELDS
|
||||
|
||||
try:
|
||||
# Configure line_spacing
|
||||
line_spacing = int(self.options['linespacing'])
|
||||
except Exception:
|
||||
# Set default value
|
||||
line_spacing = self.LINE_SPACING
|
||||
|
||||
try:
|
||||
# Configure position
|
||||
pos = self.options['position'].split(',')
|
||||
pos = [int(x.strip()) for x in pos]
|
||||
if self.options['orientation'] == "vertical":
|
||||
v_pos = (pos[0], pos[1])
|
||||
else:
|
||||
h_pos = (pos[0], pos[1])
|
||||
except Exception:
|
||||
# Set default position based on screen type
|
||||
if ui.is_waveshare_v2():
|
||||
h_pos = (178, 84)
|
||||
v_pos = (197, 74)
|
||||
elif ui.is_waveshare_v1():
|
||||
h_pos = (170, 80)
|
||||
v_pos = (165, 61)
|
||||
elif ui.is_waveshare144lcd():
|
||||
h_pos = (53, 77)
|
||||
v_pos = (73, 67)
|
||||
elif ui.is_inky():
|
||||
h_pos = (140, 68)
|
||||
v_pos = (160, 54)
|
||||
elif ui.is_waveshare27inch():
|
||||
h_pos = (192, 138)
|
||||
v_pos = (211, 122)
|
||||
else:
|
||||
h_pos = (155, 76)
|
||||
v_pos = (175, 61)
|
||||
|
||||
if self.options['orientation'] == "vertical":
|
||||
ui.set('memtemp',
|
||||
" mem:%s%%\n cpu:%s%%\ntemp:%s%s" % (self.mem_usage(), self.cpu_load(), temp, symbol))
|
||||
# Dynamically create the required LabeledValue objects
|
||||
for idx, field in enumerate(self.fields):
|
||||
v_pos_x = v_pos[0]
|
||||
v_pos_y = v_pos[1] + ((len(self.fields) - 3) * -1 * line_spacing)
|
||||
ui.add_element(
|
||||
f"memtemp_{field}",
|
||||
LabeledValue(
|
||||
color=BLACK,
|
||||
label=f"{self.pad_text(field)}:",
|
||||
value="-",
|
||||
position=(v_pos_x, v_pos_y + (idx * line_spacing)),
|
||||
label_font=fonts.Small,
|
||||
text_font=fonts.Small,
|
||||
label_spacing=self.LABEL_SPACING,
|
||||
)
|
||||
)
|
||||
else:
|
||||
# default to horizontal
|
||||
ui.set('memtemp',
|
||||
" mem cpu temp\n %s%% %s%% %s%s" % (self.mem_usage(), self.cpu_load(), temp, symbol))
|
||||
h_pos_x = h_pos[0] + ((len(self.fields) - 3) * -1 * 25)
|
||||
h_pos_y = h_pos[1]
|
||||
ui.add_element(
|
||||
'memtemp_header',
|
||||
Text(
|
||||
color=BLACK,
|
||||
value=" ".join([self.pad_text(x) for x in self.fields]),
|
||||
position=(h_pos_x, h_pos_y),
|
||||
font=fonts.Small,
|
||||
)
|
||||
)
|
||||
ui.add_element(
|
||||
'memtemp_data',
|
||||
Text(
|
||||
color=BLACK,
|
||||
value=" ".join([self.pad_text("-") for x in self.fields]),
|
||||
position=(h_pos_x, h_pos_y + line_spacing),
|
||||
font=fonts.Small,
|
||||
)
|
||||
)
|
||||
|
||||
def on_unload(self, ui):
|
||||
with ui._lock:
|
||||
if self.options['orientation'] == "vertical":
|
||||
for idx, field in enumerate(self.fields):
|
||||
ui.remove_element(f"memtemp_{field}")
|
||||
else:
|
||||
# default to horizontal
|
||||
ui.remove_element('memtemp_header')
|
||||
ui.remove_element('memtemp_data')
|
||||
|
||||
def on_ui_update(self, ui):
|
||||
if self.options['orientation'] == "vertical":
|
||||
for idx, field in enumerate(self.fields):
|
||||
ui.set(f"memtemp_{field}", getattr(self, self.ALLOWED_FIELDS[field])())
|
||||
else:
|
||||
# default to horizontal
|
||||
data = " ".join([self.pad_text(getattr(self, self.ALLOWED_FIELDS[x])()) for x in self.fields])
|
||||
ui.set('memtemp_data', data)
|
||||
|
@@ -12,7 +12,7 @@ from json.decoder import JSONDecodeError
|
||||
|
||||
class OnlineHashCrack(plugins.Plugin):
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '2.0.1'
|
||||
__version__ = '2.1.0'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin automatically uploads handshakes to https://onlinehashcrack.com'
|
||||
|
||||
@@ -55,9 +55,9 @@ class OnlineHashCrack(plugins.Plugin):
|
||||
files=payload,
|
||||
timeout=timeout)
|
||||
if 'already been sent' in result.text:
|
||||
logging.warning(f"{path} was already uploaded.")
|
||||
logging.debug(f"{path} was already uploaded.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
logging.error(f"OHC: Got an exception while uploading {path} -> {e}")
|
||||
logging.debug(f"OHC: Got an exception while uploading {path} -> {e}")
|
||||
raise e
|
||||
|
||||
def _download_cracked(self, save_file, timeout=120):
|
||||
@@ -78,6 +78,16 @@ class OnlineHashCrack(plugins.Plugin):
|
||||
except OSError as os_e:
|
||||
raise os_e
|
||||
|
||||
|
||||
def on_webhook(self, path, request):
|
||||
import requests
|
||||
from flask import redirect
|
||||
s = requests.Session()
|
||||
s.get('https://www.onlinehashcrack.com/dashboard')
|
||||
r = s.post('https://www.onlinehashcrack.com/dashboard', data={'emailTasks': self.options['email'], 'submit': ''})
|
||||
return redirect(r.url, code=302)
|
||||
|
||||
|
||||
def on_internet_available(self, agent):
|
||||
"""
|
||||
Called in manual mode when there's internet connectivity
|
||||
@@ -100,23 +110,25 @@ class OnlineHashCrack(plugins.Plugin):
|
||||
if handshake_new:
|
||||
logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onlinehashcrack.com")
|
||||
for idx, handshake in enumerate(handshake_new):
|
||||
display.set('status',
|
||||
f"Uploading handshake to onlinehashcrack.com ({idx + 1}/{len(handshake_new)})")
|
||||
display.update(force=True)
|
||||
display.on_uploading(f"onlinehashcrack.com ({idx + 1}/{len(handshake_new)})")
|
||||
|
||||
try:
|
||||
self._upload_to_ohc(handshake)
|
||||
if handshake not in reported:
|
||||
reported.append(handshake)
|
||||
self.report.update(data={'reported': reported})
|
||||
logging.info(f"OHC: Successfully uploaded {handshake}")
|
||||
logging.debug(f"OHC: Successfully uploaded {handshake}")
|
||||
except requests.exceptions.RequestException as req_e:
|
||||
self.skip.append(handshake)
|
||||
logging.error("OHC: %s", req_e)
|
||||
logging.debug("OHC: %s", req_e)
|
||||
continue
|
||||
except OSError as os_e:
|
||||
self.skip.append(handshake)
|
||||
logging.error("OHC: %s", os_e)
|
||||
logging.debug("OHC: %s", os_e)
|
||||
continue
|
||||
|
||||
display.on_normal()
|
||||
|
||||
if 'dashboard' in self.options and self.options['dashboard']:
|
||||
cracked_file = os.path.join(handshake_dir, 'onlinehashcrack.cracked')
|
||||
if os.path.exists(cracked_file):
|
||||
|
@@ -7,14 +7,18 @@
|
||||
# For Raspberry Pi Zero Ups Power Expansion Board with Integrated Serial Port S3U4
|
||||
# https://www.ebay.de/itm/For-Raspberry-Pi-Zero-Ups-Power-Expansion-Board-with-Integrated-Serial-Port-S3U4/323873804310
|
||||
# https://www.aliexpress.com/item/32888533624.html
|
||||
#
|
||||
# To display external power supply status you need to bridge the necessary pins on the UPS-Lite board. See instructions in the UPS-Lite repo.
|
||||
import logging
|
||||
import struct
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
|
||||
import pwnagotchi
|
||||
import pwnagotchi.plugins as plugins
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
from pwnagotchi.ui.components import LabeledValue
|
||||
from pwnagotchi.ui.view import BLACK
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
import pwnagotchi.plugins as plugins
|
||||
import pwnagotchi
|
||||
|
||||
|
||||
# TODO: add enable switch in config.yml an cleanup all to the best place
|
||||
@@ -43,6 +47,14 @@ class UPS:
|
||||
except:
|
||||
return 0.0
|
||||
|
||||
def charging(self):
|
||||
try:
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(4, GPIO.IN)
|
||||
return '+' if GPIO.input(4) == GPIO.HIGH else '-'
|
||||
except:
|
||||
return '-'
|
||||
|
||||
|
||||
class UPSLite(plugins.Plugin):
|
||||
__author__ = 'evilsocket@gmail.com'
|
||||
@@ -66,7 +78,8 @@ class UPSLite(plugins.Plugin):
|
||||
|
||||
def on_ui_update(self, ui):
|
||||
capacity = self.ups.capacity()
|
||||
ui.set('ups', "%2i%%" % capacity)
|
||||
charging = self.ups.charging()
|
||||
ui.set('ups', "%2i%s" % (capacity, charging))
|
||||
if capacity <= self.options['shutdown']:
|
||||
logging.info('[ups_lite] Empty battery (<= %s%%): shuting down' % self.options['shutdown'])
|
||||
ui.update(force=True, new_data={'status': 'Battery exhausted, bye ...'})
|
||||
|
36
pwnagotchi/plugins/default/watchdog.py
Normal file
36
pwnagotchi/plugins/default/watchdog.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
import subprocess
|
||||
from io import TextIOWrapper
|
||||
from pwnagotchi import plugins
|
||||
|
||||
|
||||
class Watchdog(plugins.Plugin):
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '0.1.0'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'Restart pwnagotchi when blindbug is detected.'
|
||||
|
||||
def __init__(self):
|
||||
self.options = dict()
|
||||
self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed')
|
||||
|
||||
def on_loaded(self):
|
||||
"""
|
||||
Gets called when the plugin gets loaded
|
||||
"""
|
||||
logging.info("Watchdog plugin loaded.")
|
||||
|
||||
def on_epoch(self, agent, epoch, epoch_data):
|
||||
# get last 10 lines
|
||||
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl','-n10','-k', '--since', '-5m'],
|
||||
stdout=subprocess.PIPE).stdout))[-10:])
|
||||
if len(self.pattern.findall(last_lines)) >= 5:
|
||||
display = agent.view()
|
||||
display.set('status', 'Blind-Bug detected. Restarting.')
|
||||
display.update(force=True)
|
||||
logging.info('[WATCHDOG] Blind-Bug detected. Restarting.')
|
||||
mode = 'MANU' if agent.mode == 'manual' else 'AUTO'
|
||||
import pwnagotchi
|
||||
pwnagotchi.reboot(mode=mode)
|
@@ -141,7 +141,7 @@
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
||||
subdomains: 'abcd',
|
||||
opacity:0.8,
|
||||
// maxZoom: 19
|
||||
maxZoom: 20
|
||||
});
|
||||
var mymap = L.map('mapdiv');
|
||||
|
||||
|
@@ -230,7 +230,7 @@ class Webgpsmap(plugins.Plugin):
|
||||
}
|
||||
|
||||
# get ap password if exist
|
||||
check_for = os.path.basename(pos_file[:-9]) + ".pcap.cracked"
|
||||
check_for = os.path.basename(pos_file).split(".")[0] + ".pcap.cracked"
|
||||
if check_for in all_files:
|
||||
gps_data[ssid + "_" + mac]["pass"] = pos.password()
|
||||
|
||||
|
@@ -9,6 +9,7 @@ from datetime import datetime
|
||||
from pwnagotchi.utils import WifiInfo, FieldNotFoundError, extract_from_pcap, StatusFile, remove_whitelisted
|
||||
from threading import Lock
|
||||
from pwnagotchi import plugins
|
||||
from pwnagotchi._version import __version__ as __pwnagotchi_version__
|
||||
|
||||
|
||||
def _extract_gps_data(path):
|
||||
@@ -34,14 +35,14 @@ def _format_auth(data):
|
||||
return out
|
||||
|
||||
|
||||
def _transform_wigle_entry(gps_data, pcap_data):
|
||||
def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
|
||||
"""
|
||||
Transform to wigle entry in file
|
||||
"""
|
||||
dummy = StringIO()
|
||||
# write kismet header
|
||||
dummy.write(
|
||||
"WigleWifi-1.4,appRelease=20190201,model=Kismet,release=2019.02.01.{},device=kismet,display=kismet,board=kismet,brand=kismet\n")
|
||||
"WigleWifi-1.4,appRelease={},model=pwnagotchi,release={},device=pwnagotchi,display=kismet,board=kismet,brand=pwnagotchi\n".format(plugin_version, __pwnagotchi_version__))
|
||||
dummy.write(
|
||||
"MAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type")
|
||||
|
||||
@@ -62,7 +63,7 @@ def _transform_wigle_entry(gps_data, pcap_data):
|
||||
return dummy.getvalue()
|
||||
|
||||
|
||||
def _send_to_wigle(lines, api_key, timeout=30):
|
||||
def _send_to_wigle(lines, api_key, donate=True, timeout=30):
|
||||
"""
|
||||
Uploads the file to wigle-net
|
||||
"""
|
||||
@@ -76,7 +77,7 @@ def _send_to_wigle(lines, api_key, timeout=30):
|
||||
|
||||
headers = {'Authorization': f"Basic {api_key}",
|
||||
'Accept': 'application/json'}
|
||||
data = {'donate': 'false'}
|
||||
data = {'donate': 'on' if donate else 'false'}
|
||||
payload = {'file': dummy, 'type': 'text/csv'}
|
||||
|
||||
try:
|
||||
@@ -106,12 +107,15 @@ class Wigle(plugins.Plugin):
|
||||
|
||||
def on_loaded(self):
|
||||
if 'api_key' not in self.options or ('api_key' in self.options and self.options['api_key'] is None):
|
||||
logging.error("WIGLE: api_key isn't set. Can't upload to wigle.net")
|
||||
logging.debug("WIGLE: api_key isn't set. Can't upload to wigle.net")
|
||||
return
|
||||
|
||||
if not 'whitelist' in self.options:
|
||||
self.options['whitelist'] = list()
|
||||
|
||||
if not 'donate' in self.options:
|
||||
self.options['donate'] = True
|
||||
|
||||
self.ready = True
|
||||
|
||||
def on_internet_available(self, agent):
|
||||
@@ -141,21 +145,21 @@ class Wigle(plugins.Plugin):
|
||||
for gps_file in new_gps_files:
|
||||
pcap_filename = gps_file.replace('.gps.json', '.pcap')
|
||||
if not os.path.exists(pcap_filename):
|
||||
logging.error("WIGLE: Can't find pcap for %s", gps_file)
|
||||
logging.debug("WIGLE: Can't find pcap for %s", gps_file)
|
||||
self.skip.append(gps_file)
|
||||
continue
|
||||
try:
|
||||
gps_data = _extract_gps_data(gps_file)
|
||||
except OSError as os_err:
|
||||
logging.error("WIGLE: %s", os_err)
|
||||
logging.debug("WIGLE: %s", os_err)
|
||||
self.skip.append(gps_file)
|
||||
continue
|
||||
except json.JSONDecodeError as json_err:
|
||||
logging.error("WIGLE: %s", json_err)
|
||||
logging.debug("WIGLE: %s", json_err)
|
||||
self.skip.append(gps_file)
|
||||
continue
|
||||
if gps_data['Latitude'] == 0 and gps_data['Longitude'] == 0:
|
||||
logging.warning("WIGLE: Not enough gps-information for %s. Trying again next time.", gps_file)
|
||||
logging.debug("WIGLE: Not enough gps-information for %s. Trying again next time.", gps_file)
|
||||
self.skip.append(gps_file)
|
||||
continue
|
||||
try:
|
||||
@@ -165,27 +169,29 @@ class Wigle(plugins.Plugin):
|
||||
WifiInfo.CHANNEL,
|
||||
WifiInfo.RSSI])
|
||||
except FieldNotFoundError:
|
||||
logging.error("WIGLE: Could not extract all information. Skip %s", gps_file)
|
||||
logging.debug("WIGLE: Could not extract all information. Skip %s", gps_file)
|
||||
self.skip.append(gps_file)
|
||||
continue
|
||||
except Scapy_Exception as sc_e:
|
||||
logging.error("WIGLE: %s", sc_e)
|
||||
logging.debug("WIGLE: %s", sc_e)
|
||||
self.skip.append(gps_file)
|
||||
continue
|
||||
new_entry = _transform_wigle_entry(gps_data, pcap_data)
|
||||
new_entry = _transform_wigle_entry(gps_data, pcap_data, self.__version__)
|
||||
csv_entries.append(new_entry)
|
||||
no_err_entries.append(gps_file)
|
||||
if csv_entries:
|
||||
display.set('status', "Uploading gps-data to wigle.net ...")
|
||||
display.update(force=True)
|
||||
display.on_uploading('wigle.net')
|
||||
|
||||
try:
|
||||
_send_to_wigle(csv_entries, self.options['api_key'])
|
||||
_send_to_wigle(csv_entries, self.options['api_key'], donate=self.options['donate'])
|
||||
reported += no_err_entries
|
||||
self.report.update(data={'reported': reported})
|
||||
logging.info("WIGLE: Successfully uploaded %d files", len(no_err_entries))
|
||||
except requests.exceptions.RequestException as re_e:
|
||||
self.skip += no_err_entries
|
||||
logging.error("WIGLE: Got an exception while uploading %s", re_e)
|
||||
logging.debug("WIGLE: Got an exception while uploading %s", re_e)
|
||||
except OSError as os_e:
|
||||
self.skip += no_err_entries
|
||||
logging.error("WIGLE: Got the following error: %s", os_e)
|
||||
logging.debug("WIGLE: Got the following error: %s", os_e)
|
||||
|
||||
display.on_normal()
|
||||
|
@@ -39,7 +39,7 @@ class WpaSec(plugins.Plugin):
|
||||
files=payload,
|
||||
timeout=timeout)
|
||||
if ' already submitted' in result.text:
|
||||
logging.warning("%s was already submitted.", path)
|
||||
logging.debug("%s was already submitted.", path)
|
||||
except requests.exceptions.RequestException as req_e:
|
||||
raise req_e
|
||||
|
||||
@@ -82,6 +82,13 @@ class WpaSec(plugins.Plugin):
|
||||
self.options['whitelist'] = list()
|
||||
|
||||
self.ready = True
|
||||
logging.info("WPA_SEC: plugin loaded")
|
||||
|
||||
def on_webhook(self, path, request):
|
||||
from flask import make_response, redirect
|
||||
response = make_response(redirect(self.options['api_url'], code=302))
|
||||
response.set_cookie('key', self.options['api_key'])
|
||||
return response
|
||||
|
||||
def on_internet_available(self, agent):
|
||||
"""
|
||||
@@ -104,21 +111,23 @@ class WpaSec(plugins.Plugin):
|
||||
if handshake_new:
|
||||
logging.info("WPA_SEC: Internet connectivity detected. Uploading new handshakes to wpa-sec.stanev.org")
|
||||
for idx, handshake in enumerate(handshake_new):
|
||||
display.set('status', f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new)})")
|
||||
display.update(force=True)
|
||||
display.on_uploading(f"wpa-sec.stanev.org ({idx + 1}/{len(handshake_new)})")
|
||||
|
||||
try:
|
||||
self._upload_to_wpasec(handshake)
|
||||
reported.append(handshake)
|
||||
self.report.update(data={'reported': reported})
|
||||
logging.info("WPA_SEC: Successfully uploaded %s", handshake)
|
||||
logging.debug("WPA_SEC: Successfully uploaded %s", handshake)
|
||||
except requests.exceptions.RequestException as req_e:
|
||||
self.skip.append(handshake)
|
||||
logging.error("WPA_SEC: %s", req_e)
|
||||
logging.debug("WPA_SEC: %s", req_e)
|
||||
continue
|
||||
except OSError as os_e:
|
||||
logging.error("WPA_SEC: %s", os_e)
|
||||
logging.debug("WPA_SEC: %s", os_e)
|
||||
continue
|
||||
|
||||
display.on_normal()
|
||||
|
||||
if 'download_results' in self.options and self.options['download_results']:
|
||||
cracked_file = os.path.join(handshake_dir, 'wpa-sec.cracked.potfile')
|
||||
if os.path.exists(cracked_file):
|
||||
|
@@ -49,8 +49,11 @@ class Display(View):
|
||||
def is_lcdhat(self):
|
||||
return self._implementation.name == 'lcdhat'
|
||||
|
||||
def is_dfrobot(self):
|
||||
return self._implementation.name == 'dfrobot'
|
||||
def is_dfrobot_v1(self):
|
||||
return self._implementation.name == 'dfrobot_v1'
|
||||
|
||||
def is_dfrobot_v2(self):
|
||||
return self._implementation.name == 'dfrobot_v2'
|
||||
|
||||
def is_waveshare144lcd(self):
|
||||
return self._implementation.name == 'waveshare144lcd'
|
||||
|
@@ -20,7 +20,9 @@ ANGRY = "(-_-')"
|
||||
FRIEND = '(♥‿‿♥)'
|
||||
BROKEN = '(☓‿‿☓)'
|
||||
DEBUG = '(#__#)'
|
||||
|
||||
UPLOAD = '(1__0)'
|
||||
UPLOAD1 = '(1__1)'
|
||||
UPLOAD2 = '(0__1)'
|
||||
|
||||
def load_from_config(config):
|
||||
for face_name, face_value in config.items():
|
||||
|
@@ -2,7 +2,8 @@ from pwnagotchi.ui.hw.inky import Inky
|
||||
from pwnagotchi.ui.hw.papirus import Papirus
|
||||
from pwnagotchi.ui.hw.oledhat import OledHat
|
||||
from pwnagotchi.ui.hw.lcdhat import LcdHat
|
||||
from pwnagotchi.ui.hw.dfrobot import DFRobot
|
||||
from pwnagotchi.ui.hw.dfrobot1 import DFRobotV1
|
||||
from pwnagotchi.ui.hw.dfrobot2 import DFRobotV2
|
||||
from pwnagotchi.ui.hw.waveshare1 import WaveshareV1
|
||||
from pwnagotchi.ui.hw.waveshare2 import WaveshareV2
|
||||
from pwnagotchi.ui.hw.waveshare27inch import Waveshare27inch
|
||||
@@ -27,8 +28,11 @@ def display_for(config):
|
||||
if config['ui']['display']['type'] == 'lcdhat':
|
||||
return LcdHat(config)
|
||||
|
||||
if config['ui']['display']['type'] == 'dfrobot':
|
||||
return DFRobot(config)
|
||||
if config['ui']['display']['type'] == 'dfrobot_1':
|
||||
return DFRobotV1(config)
|
||||
|
||||
if config['ui']['display']['type'] == 'dfrobot_2':
|
||||
return DFRobotV2(config)
|
||||
|
||||
elif config['ui']['display']['type'] == 'waveshare_1':
|
||||
return WaveshareV1(config)
|
||||
|
@@ -3,9 +3,9 @@ import logging
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||
|
||||
class DFRobot(DisplayImpl):
|
||||
class DFRobotV1(DisplayImpl):
|
||||
def __init__(self, config):
|
||||
super(DFRobot, self).__init__(config, 'dfrobot')
|
||||
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
|
||||
self._display = None
|
||||
|
||||
def layout(self):
|
||||
@@ -31,8 +31,8 @@ class DFRobot(DisplayImpl):
|
||||
return self._layout
|
||||
|
||||
def initialize(self):
|
||||
logging.info("initializing dfrobot display")
|
||||
from pwnagotchi.ui.hw.libs.dfrobot.dfrobot import DFRobot
|
||||
logging.info("initializing dfrobot1 display")
|
||||
from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot
|
||||
self._display = DFRobot()
|
||||
|
||||
def render(self, canvas):
|
43
pwnagotchi/ui/hw/dfrobot2.py
Normal file
43
pwnagotchi/ui/hw/dfrobot2.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import logging
|
||||
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||
|
||||
class DFRobotV2(DisplayImpl):
|
||||
def __init__(self, config):
|
||||
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
|
||||
self._display = None
|
||||
|
||||
def layout(self):
|
||||
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||
self._layout['width'] = 250
|
||||
self._layout['height'] = 122
|
||||
self._layout['face'] = (0, 40)
|
||||
self._layout['name'] = (5, 20)
|
||||
self._layout['channel'] = (0, 0)
|
||||
self._layout['aps'] = (28, 0)
|
||||
self._layout['uptime'] = (185, 0)
|
||||
self._layout['line1'] = [0, 14, 250, 14]
|
||||
self._layout['line2'] = [0, 108, 250, 108]
|
||||
self._layout['friend_face'] = (0, 92)
|
||||
self._layout['friend_name'] = (40, 94)
|
||||
self._layout['shakes'] = (0, 109)
|
||||
self._layout['mode'] = (225, 109)
|
||||
self._layout['status'] = {
|
||||
'pos': (125, 20),
|
||||
'font': fonts.status_font(fonts.Medium),
|
||||
'max': 20
|
||||
}
|
||||
return self._layout
|
||||
|
||||
def initialize(self):
|
||||
logging.info("initializing dfrobot2 display")
|
||||
from pwnagotchi.ui.hw.libs.dfrobot.v2.dfrobot import DFRobot
|
||||
self._display = DFRobot()
|
||||
|
||||
def render(self, canvas):
|
||||
buf = self._display.getbuffer(canvas)
|
||||
self._display.display(buf)
|
||||
|
||||
def clear(self):
|
||||
self._display.Clear(0xFF)
|
@@ -42,6 +42,12 @@ class Inky(DisplayImpl):
|
||||
from pwnagotchi.ui.hw.libs.inkyphat.inkyphatfast import InkyPHATFast
|
||||
self._display = InkyPHATFast('black')
|
||||
self._display.set_border(InkyPHATFast.BLACK)
|
||||
elif self.config['color'] == 'auto':
|
||||
from inky.auto import auto
|
||||
self._display = auto()
|
||||
self._display.set_border(self._display.BLACK)
|
||||
self._layout['width'] = self._display.WIDTH
|
||||
self._layout['height'] = self._display.HEIGHT
|
||||
else:
|
||||
from inky import InkyPHAT
|
||||
self._display = InkyPHAT(self.config['color'])
|
||||
|
0
pwnagotchi/ui/hw/libs/dfrobot/v1/__init__.py
Normal file
0
pwnagotchi/ui/hw/libs/dfrobot/v1/__init__.py
Normal file
0
pwnagotchi/ui/hw/libs/dfrobot/v2/__init__.py
Normal file
0
pwnagotchi/ui/hw/libs/dfrobot/v2/__init__.py
Normal file
66
pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot.py
Normal file
66
pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# DFRobot display support
|
||||
|
||||
import logging
|
||||
from . import dfrobot_epaper
|
||||
|
||||
#Resolution of display
|
||||
WIDTH = 250
|
||||
HEIGHT = 122
|
||||
|
||||
RASPBERRY_SPI_BUS = 0
|
||||
RASPBERRY_SPI_DEV = 0
|
||||
RASPBERRY_PIN_CS = 27
|
||||
RASPBERRY_PIN_CD = 17
|
||||
RASPBERRY_PIN_BUSY = 4
|
||||
|
||||
class DFRobot:
|
||||
def __init__(self):
|
||||
self._display = dfrobot_epaper.DFRobot_Epaper_SPI(RASPBERRY_SPI_BUS, RASPBERRY_SPI_DEV, RASPBERRY_PIN_CS, RASPBERRY_PIN_CD, RASPBERRY_PIN_BUSY)
|
||||
self._display.begin()
|
||||
self.clear(0xFF)
|
||||
self.FULL = self._display.FULL
|
||||
self.PART = self._display.PART
|
||||
|
||||
def getbuffer(self, image):
|
||||
if HEIGHT % 8 == 0:
|
||||
linewidth = HEIGHT // 8
|
||||
else:
|
||||
linewidth = HEIGHT // 8 + 1
|
||||
|
||||
buf = [0xFF] * (linewidth * WIDTH)
|
||||
image_monocolor = image.convert('1')
|
||||
imwidth, imheight = image_monocolor.size
|
||||
pixels = image_monocolor.load()
|
||||
|
||||
if (imwidth == HEIGHT and imheight == WIDTH):
|
||||
for y in range(imheight):
|
||||
for x in range(imwidth):
|
||||
if pixels[x,y] == 0:
|
||||
x = imwidth - x
|
||||
buf[x // 8 + y * linewidth] &= ~(0x80 >> (x % 8))
|
||||
elif (imwidth == WIDTH and imheight == HEIGHT):
|
||||
for y in range(imheight):
|
||||
for x in range(imwidth):
|
||||
newx = y
|
||||
newy = WIDTH - x - 1
|
||||
if pixels[x,y] == 0:
|
||||
newy = imwidth - newy - 1
|
||||
buf[newx // 8 + newy * linewidth] &= ~(0x80 >> (y % 8))
|
||||
return buf
|
||||
|
||||
def flush(self, type):
|
||||
self._display.flush(type)
|
||||
|
||||
def display(self, buf):
|
||||
self._display.setBuffer(buf)
|
||||
self.flush(self._display.PART)
|
||||
|
||||
def clear(self, color):
|
||||
if HEIGHT % 8 == 0:
|
||||
linewidth = HEIGHT // 8
|
||||
else:
|
||||
linewidth = HEIGHT // 8 + 1
|
||||
|
||||
buf = [color] * (linewidth * WIDTH)
|
||||
self._display.setBuffer(buf)
|
||||
self.flush(self._display.FULL)
|
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/__init__.pyc
Normal file
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/__init__.pyc
Normal file
Binary file not shown.
@@ -0,0 +1,673 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import sys
|
||||
|
||||
from .dfrobot_printString import PrintString
|
||||
from .dfrobot_fonts import Fonts
|
||||
|
||||
def color24to16(color):
|
||||
return (((color >> 8) & 0xf800) | ((color >> 5) & 0x7e0) | ((color >> 3) & 0x1f))
|
||||
|
||||
def color16to24(color):
|
||||
return (((color & 0xf800) << 8) | ((color & 0x7e0) << 5) | ((color & 0x1f) << 3))
|
||||
|
||||
def swap(o1, o2):
|
||||
return (o2, o1)
|
||||
|
||||
class DFRobot_Display(PrintString):
|
||||
|
||||
WHITE24 = 0xffffff
|
||||
SILVER24 = 0xc0c0c0
|
||||
GRAY24 = 0x808080
|
||||
BLACK24 = 0x000000
|
||||
RED24 = 0xff0000
|
||||
MAROON24 = 0x800000
|
||||
YELLOW24 = 0xffff00
|
||||
OLIVE24 = 0x808000
|
||||
GREEN24 = 0x00ff00
|
||||
DARKGREEN24 = 0x008000
|
||||
CYAN24 = 0x00ffff
|
||||
BLUE24 = 0x0000ff
|
||||
NAVY24 = 0x000080
|
||||
FUCHSIA24 = 0xff00ff
|
||||
PURPLE24 = 0x800080
|
||||
TEAL24 = 0x008080
|
||||
|
||||
WHITE16 = color24to16(WHITE24)
|
||||
SILVER16 = color24to16(SILVER24)
|
||||
GRAY16 = color24to16(GRAY24)
|
||||
BLACK16 = color24to16(BLACK24)
|
||||
RED16 = color24to16(RED24)
|
||||
MAROON16 = color24to16(MAROON24)
|
||||
YELLOW16 = color24to16(YELLOW24)
|
||||
OLIVE16 = color24to16(OLIVE24)
|
||||
GREEN16 = color24to16(GREEN24)
|
||||
DARKGREEN16 = color24to16(DARKGREEN24)
|
||||
CYAN16 = color24to16(CYAN24)
|
||||
BLUE16 = color24to16(BLUE24)
|
||||
NAVY16 = color24to16(NAVY24)
|
||||
FUCHSIA16 = color24to16(FUCHSIA24)
|
||||
PURPLE16 = color24to16(PURPLE24)
|
||||
TEAL16 = color24to16(TEAL24)
|
||||
|
||||
WHITE = WHITE16
|
||||
SILVER = SILVER16
|
||||
GRAY = GRAY16
|
||||
BLACK = BLACK16
|
||||
RED = RED16
|
||||
MAROON = MAROON16
|
||||
YELLOW = YELLOW16
|
||||
OLIVE = OLIVE16
|
||||
GREEN = GREEN16
|
||||
DARKGREEN = DARKGREEN16
|
||||
CYAN = CYAN16
|
||||
BLUE = BLUE16
|
||||
NAVY = NAVY16
|
||||
FUCHSIA = FUCHSIA16
|
||||
PURPLE = PURPLE16
|
||||
TEAL = TEAL16
|
||||
|
||||
POSITIVE = 1
|
||||
REVERSE = -1
|
||||
|
||||
BITMAP_TBMLLR = "TBMLLR"
|
||||
BITMAP_TBMRLL = "TBMRLL"
|
||||
BITMAP_BTMLLR = "BTMLLR"
|
||||
BITMAP_BTMRLL = "BTMRLL"
|
||||
BITMAP_LRMTLB = "LRMTLB"
|
||||
BITMAP_LRMBLT = "LRMBLT"
|
||||
BITMAP_RLMTLB = "RLMTLB"
|
||||
BIMTAP_RLMBLT = "RLMBLT"
|
||||
BITMAP_UNKNOW = "UNKNOW"
|
||||
|
||||
def __init__(self, w, h):
|
||||
PrintString.__init__(self)
|
||||
print("DFRobot_Display init " + str(w) + " " + str(h))
|
||||
self._width = w
|
||||
self._height = h
|
||||
|
||||
self._lineWidth = 1
|
||||
self._bitmapSize = 1
|
||||
self._bitmapFmt = ""
|
||||
self._bmpFmt = self.BITMAP_TBMLLR
|
||||
|
||||
self._fonts = Fonts()
|
||||
self._textSize = 1
|
||||
self._textColor = self.BLACK
|
||||
self._textBackground = self.WHITE
|
||||
self._textCursorX = 0
|
||||
self._textCursorY = 0
|
||||
self._textIntervalRow = 0
|
||||
self._textIntervalCol = 0
|
||||
|
||||
def _ternaryExpression(self, condition, o1, o2):
|
||||
if condition:
|
||||
return o1
|
||||
return o2
|
||||
|
||||
def _getDirection(self, value):
|
||||
if value >= 0:
|
||||
return 1
|
||||
return -1
|
||||
|
||||
def color16to24(self, color):
|
||||
return color16to24(color)
|
||||
|
||||
def color24to16(self, color):
|
||||
return color24to16(color)
|
||||
|
||||
def setColorTo16(self):
|
||||
self.WHITE = self.WHITE16
|
||||
self.SILVER = self.SILVER16
|
||||
self.GRAY = self.GRAY16
|
||||
self.BLACK = self.BLACK16
|
||||
self.RED = self.RED16
|
||||
self.MAROON = self.MAROON16
|
||||
self.YELLOW = self.YELLOW16
|
||||
self.OLIVE = self.OLIVE16
|
||||
self.GREEN = self.GREEN16
|
||||
self.DARKGREEN = self.DARKGREEN16
|
||||
self.CYAN = self.CYAN16
|
||||
self.BLUE = self.BLUE16
|
||||
self.NAVY = self.NAVY16
|
||||
self.FUCHSIA = self.FUCHSIA16
|
||||
self.PURPLE = self.PURPLE16
|
||||
self.TEAL = self.TEAL16
|
||||
|
||||
def setColorTo24(self):
|
||||
self.WHITE = self.WHITE24
|
||||
self.SILVER = self.SILVER24
|
||||
self.GRAY = self.GRAY24
|
||||
self.BLACK = self.BLACK24
|
||||
self.RED = self.RED24
|
||||
self.MAROON = self.MAROON24
|
||||
self.YELLOW = self.YELLOW24
|
||||
self.OLIVE = self.OLIVE24
|
||||
self.GREEN = self.GREEN24
|
||||
self.DARKGREEN = self.DARKGREEN24
|
||||
self.CYAN = self.CYAN24
|
||||
self.BLUE = self.BLUE24
|
||||
self.NAVY = self.NAVY24
|
||||
self.FUCHSIA = self.FUCHSIA24
|
||||
self.PURPLE = self.PURPLE24
|
||||
self.TEAL = self.TEAL24
|
||||
|
||||
def setLineWidth(self, w):
|
||||
if w < 0:
|
||||
return
|
||||
self._lineWidth = w
|
||||
|
||||
def setTextFormat(self, size, color, background, intervalRow = 2, intervalCol = 0):
|
||||
self._textColor = color
|
||||
self._textIntervalRow = intervalRow
|
||||
self._textIntervalCol = intervalCol
|
||||
self._textBackground = background
|
||||
if size < 0:
|
||||
return
|
||||
self._textSize = size
|
||||
|
||||
def setTextCursor(self, x, y):
|
||||
self._textCursorX = int(x)
|
||||
self._textCursorY = int(y)
|
||||
|
||||
def setBitmapSize(self, size):
|
||||
if size < 0:
|
||||
return
|
||||
self._bitmapSize = size
|
||||
|
||||
def setBitmapFmt(self, fmt):
|
||||
self._bmpFmt = fmt
|
||||
|
||||
def setExFonts(self, obj):
|
||||
self._fonts.setExFonts(obj)
|
||||
|
||||
def setExFontsFmt(self, width, height):
|
||||
self._fonts.setExFontsFmt(width, height)
|
||||
|
||||
def setEnableDefaultFonts(self, opt):
|
||||
self._fonts.setEnableDefaultFonts(opt)
|
||||
|
||||
def pixel(self, x, y, color):
|
||||
pass
|
||||
|
||||
def clear(self, color):
|
||||
self.fillRect(0, 0, self._width, self._height, color)
|
||||
self._textCursorX = 0
|
||||
self._textCursorY = 0
|
||||
|
||||
def VLine(self, x, y, h, color):
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
h = int(h)
|
||||
direction = self._getDirection(h)
|
||||
x -= self._lineWidth // 2
|
||||
h = self._ternaryExpression(h > 0, h, -h)
|
||||
for i in range(self._ternaryExpression(h > 0, h, - h)):
|
||||
xx = x
|
||||
for j in range(self._lineWidth):
|
||||
self.pixel(xx, y, color)
|
||||
xx += 1
|
||||
y += direction
|
||||
|
||||
def HLine(self, x, y, w, color):
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
w = int(w)
|
||||
direction = self._getDirection(w)
|
||||
y -= self._lineWidth // 2
|
||||
for i in range(self._ternaryExpression(w > 0, w, - w)):
|
||||
yy = y
|
||||
for j in range(self._lineWidth):
|
||||
self.pixel(x, yy, color)
|
||||
yy += 1
|
||||
x += direction
|
||||
|
||||
def line(self, x, y, x1, y1, color):
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
x1 = int(x1)
|
||||
y1 = int(y1)
|
||||
if x == x1:
|
||||
self.VLine(x, y, y1 - y, color)
|
||||
return
|
||||
if y == y1:
|
||||
self.HLine(x, y, x1 - x, color)
|
||||
return
|
||||
dx = abs(x1 - x)
|
||||
dy = abs(y1 - y)
|
||||
dirX = self._ternaryExpression(x < x1, 1, -1)
|
||||
dirY = self._ternaryExpression(y < y1, 1, -1)
|
||||
if dx > dy:
|
||||
err = dx / 2
|
||||
for i in range(dx):
|
||||
self.HLine(x, y, 1, color)
|
||||
x += dirX
|
||||
err -= dy
|
||||
if err < 0:
|
||||
err += dx
|
||||
y += dirY
|
||||
self.HLine(x1, y1, 1, color)
|
||||
else:
|
||||
err = dy / 2
|
||||
for i in range(dy):
|
||||
self.VLine(x, y, 1, color)
|
||||
y += dirY
|
||||
err -= dx
|
||||
if err < 0:
|
||||
err += dy
|
||||
x += dirX
|
||||
self.VLine(x1, y1, 1, color)
|
||||
|
||||
def triangle(self, x, y, x1, y1, x2, y2, color):
|
||||
self.line(x, y, x1, y1, color)
|
||||
self.line(x1, y1, x2, y2, color)
|
||||
self.line(x2, y2, x, y, color)
|
||||
|
||||
def fillTriangle(self, x, y, x1, y1, x2, y2, color):
|
||||
self.line(x, y, x1, y1, color)
|
||||
self.line(x1, y1, x2, y2, color)
|
||||
self.line(x2, y2, x, y, color)
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
x1 = int(x1)
|
||||
y1 = int(y1)
|
||||
x2 = int(x2)
|
||||
y2 = int(y2)
|
||||
temp = self._lineWidth
|
||||
self._lineWidth = 1
|
||||
if x == x1 and x == x2:
|
||||
ymax = max([y, y1, y2])
|
||||
ymin = min([y, y1, y2])
|
||||
self.HLine(x, ymin, ymax - ymin, color)
|
||||
self._lineWidth = temp
|
||||
return
|
||||
if y == y1 and y == y2:
|
||||
xmax = max([x, x1, x2])
|
||||
xmin = max([x, x1, x2])
|
||||
self.VLine(xmin, y, xmax - xmin, color)
|
||||
self._lineWidth = temp
|
||||
return
|
||||
|
||||
direction = self.POSITIVE
|
||||
if y == y1 or y1 == y2 or y == y2:
|
||||
if y == y1:
|
||||
(x, x2) = swap(x, x2)
|
||||
(y, y2) = swap(y, y2)
|
||||
elif y == y2:
|
||||
(x, x1) = swap(x, x1)
|
||||
(y, y1) = swap(y, y1)
|
||||
if y > y1:
|
||||
direction = self.REVERSE
|
||||
if x1 > x2:
|
||||
(x1, x2) = swap(x1, x2)
|
||||
(y1, y2) = swap(y1, y2)
|
||||
else:
|
||||
if y > y1:
|
||||
(x, x1) = swap(x, x1)
|
||||
(y, y1) = swap(y, y1)
|
||||
if y > y2:
|
||||
(x, x2) = swap(x, x2)
|
||||
(y, y2) = swap(y, y2)
|
||||
if y1 > y2:
|
||||
(x1, x2) = swap(x1, x2)
|
||||
(y1, y2) = swap(y1, y2)
|
||||
|
||||
dx1 = x1 - x
|
||||
dx2 = x2 - x
|
||||
dx3 = x2 - x1
|
||||
dy1 = y1 - y
|
||||
dy2 = y2 - y
|
||||
dy3 = y2 - y1
|
||||
if direction == self.POSITIVE:
|
||||
for i in range(dy1):
|
||||
self.HLine(x + dx1 * i / dy1, y + i, (x + dx2 * i / dy2) - (x + dx1 * i / dy1) + 1, color)
|
||||
for i in range(dy3):
|
||||
self.HLine(x1 + dx3 * i / dy3, y1 + i, (x + dx2 * (i + dy1) / dy2) - (x1 + dx3 * i / dy3) + 1, color)
|
||||
else:
|
||||
y = y1 + dy1
|
||||
dy1 = - dy1
|
||||
for i in range(dy1):
|
||||
self.HLine(x + dx1 * i / dy1, y1 + dy1 - i, (x + dx2 * i / dy1) - (x + dx1 * i / dy1) + 1, color)
|
||||
self._lineWidth = temp
|
||||
|
||||
def rect(self, x, y, w, h, color):
|
||||
if w < 0:
|
||||
x += w
|
||||
w = -w
|
||||
if h < 0:
|
||||
y += h
|
||||
h = -h
|
||||
self.HLine(x - self._lineWidth // 2, y, w + self._lineWidth, color)
|
||||
self.HLine(x - self._lineWidth // 2, y + h, w + self._lineWidth, color)
|
||||
self.VLine(x, y - self._lineWidth // 2, h + self._lineWidth, color)
|
||||
self.VLine(x + w, y - self._lineWidth // 2, h + self._lineWidth, color)
|
||||
|
||||
def fillRect(self, x, y, w, h, color):
|
||||
temp = self._lineWidth
|
||||
self._lineWidth = 1
|
||||
if w < 0:
|
||||
x += w
|
||||
w = abs(w)
|
||||
for i in range(w):
|
||||
self.VLine(x + i, y, h, color)
|
||||
self._lineWidth = temp
|
||||
|
||||
QUADRANT_1 = 1
|
||||
QUADRANT_2 = 2
|
||||
QUADRANT_3 = 4
|
||||
QUADRANT_4 = 8
|
||||
QUADRANT_ALL = 15
|
||||
|
||||
def circleHelper(self, x, y, r, quadrant, color):
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
r = abs(int(r))
|
||||
vx = 0
|
||||
vy = r
|
||||
dx = 1
|
||||
dy = -2 * r
|
||||
p = 1 - r
|
||||
if quadrant & self.QUADRANT_1:
|
||||
self.VLine(x + r, y, 1, color)
|
||||
if quadrant & self.QUADRANT_2:
|
||||
self.VLine(x, y - r, 1, color)
|
||||
if quadrant & self.QUADRANT_3:
|
||||
self.VLine(x - r, y, 1, color)
|
||||
if quadrant & self.QUADRANT_4:
|
||||
self.VLine(x, y + r, 1, color)
|
||||
|
||||
halfLineWidth = self._lineWidth // 2
|
||||
while vx < vy:
|
||||
if p >= 0:
|
||||
vy -= 1
|
||||
dy += 2
|
||||
p += dy
|
||||
vx += 1
|
||||
dx += 2
|
||||
p += dx
|
||||
if quadrant & self.QUADRANT_1:
|
||||
self.fillRect(x + vx - halfLineWidth, y - vy - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 1
|
||||
self.fillRect(x + vy - halfLineWidth, y - vx - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 1
|
||||
if quadrant & self.QUADRANT_2:
|
||||
self.fillRect(x - vx - halfLineWidth, y - vy - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 2
|
||||
self.fillRect(x - vy - halfLineWidth, y - vx - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 2
|
||||
if quadrant & self.QUADRANT_3:
|
||||
self.fillRect(x - vx - halfLineWidth, y + vy - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 3
|
||||
self.fillRect(x - vy - halfLineWidth, y + vx - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 3
|
||||
if quadrant & self.QUADRANT_4:
|
||||
self.fillRect(x + vx - halfLineWidth, y + vy - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 4
|
||||
self.fillRect(x + vy - halfLineWidth, y + vx - halfLineWidth, self._lineWidth, self._lineWidth, color) # quadrant 4
|
||||
|
||||
def circle(self, x, y, r, color):
|
||||
self.circleHelper(x, y, r, self.QUADRANT_ALL, color)
|
||||
|
||||
def fillCircleHelper(self, x, y, r, quadrant, color):
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
r = abs(int(r))
|
||||
temp = self._lineWidth
|
||||
self._lineWidth = 1
|
||||
vx = 0
|
||||
vy = r
|
||||
dx = 1
|
||||
dy = -2 * r
|
||||
p = 1 - r
|
||||
if quadrant & self.QUADRANT_1:
|
||||
self.HLine(x, y, r + 1, color)
|
||||
if quadrant & self.QUADRANT_2:
|
||||
self.VLine(x, y, - r - 1, color)
|
||||
if quadrant & self.QUADRANT_3:
|
||||
self.HLine(x, y, - r - 1, color)
|
||||
if quadrant & self.QUADRANT_4:
|
||||
self.VLine(x, y, r + 1, color)
|
||||
|
||||
while vx < vy:
|
||||
if p >= 0:
|
||||
vy -= 1
|
||||
dy += 2
|
||||
p += dy
|
||||
vx += 1
|
||||
dx += 2
|
||||
p += dx
|
||||
if quadrant & self.QUADRANT_1:
|
||||
self.VLine(x + vx, y - vy, vy, color) # quadrant 1
|
||||
self.VLine(x + vy, y - vx, vx, color) # quadrant 1
|
||||
if quadrant & self.QUADRANT_2:
|
||||
self.VLine(x - vx, y - vy, vy, color) # quadrant 2
|
||||
self.VLine(x - vy, y - vx, vx, color) # quadrant 2
|
||||
if quadrant & self.QUADRANT_3:
|
||||
self.VLine(x - vx, y + vy, - vy, color) # quadrant 3
|
||||
self.VLine(x - vy, y + vx, - vx, color) # quadrant 3
|
||||
if quadrant & self.QUADRANT_4:
|
||||
self.VLine(x + vx, y + vy, - vy, color) # quadrant 4
|
||||
self.VLine(x + vy, y + vx, - vx, color) # quadrant 4
|
||||
self._lineWidth = temp
|
||||
|
||||
def fillCircle(self, x, y, r, color):
|
||||
self.fillCircleHelper(x, y, r, self.QUADRANT_ALL, color)
|
||||
|
||||
def roundRect(self, x, y, w, h, r, color):
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
w = int(w)
|
||||
h = int(h)
|
||||
r = abs(int(r))
|
||||
if w < 0:
|
||||
x += w
|
||||
w = abs(w)
|
||||
if h < 0:
|
||||
y += h
|
||||
h = abs(h)
|
||||
self.HLine(x + r, y, w - 2 * r + 1, color)
|
||||
self.HLine(x + r, y + h, w - 2 * r + 1, color)
|
||||
self.VLine(x, y + r, h - 2 * r + 1, color)
|
||||
self.VLine(x + w, y + r, h - 2 * r + 1, color)
|
||||
self.circleHelper(x + r, y + r, r, self.QUADRANT_2, color)
|
||||
self.circleHelper(x + w - r, y + r, r, self.QUADRANT_1, color)
|
||||
self.circleHelper(x + r, y + h - r, r, self.QUADRANT_3, color)
|
||||
self.circleHelper(x + w - r, y + h - r, r, self.QUADRANT_4, color)
|
||||
|
||||
def fillRoundRect(self, x, y, w, h, r, color):
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
w = int(w)
|
||||
h = int(h)
|
||||
r = abs(int(r))
|
||||
if w < 0:
|
||||
x += w
|
||||
w = abs(w)
|
||||
if h < 0:
|
||||
y += h
|
||||
h = abs(h)
|
||||
self.fillRect(x + r, y, w - 2 * r, h, color)
|
||||
self.fillRect(x, y + r, r, h - 2 * r, color)
|
||||
self.fillRect(x + w - r, y + r, r, h - 2 * r, color)
|
||||
self.fillCircleHelper(x + r, y + r, r, self.QUADRANT_2, color)
|
||||
self.fillCircleHelper(x + w - r - 1, y + r, r, self.QUADRANT_1, color)
|
||||
self.fillCircleHelper(x + r, y + h - r - 1, r, self.QUADRANT_3, color)
|
||||
self.fillCircleHelper(x + w - r - 1, y + h - r - 1, r, self.QUADRANT_4, color)
|
||||
|
||||
def _bitmapHelper(self, increaseAxis, staticAxis, data, dataBit, exchange, color, background):
|
||||
for i in data:
|
||||
for j in range(8):
|
||||
if i & dataBit:
|
||||
if exchange:
|
||||
self.fillRect(staticAxis, increaseAxis, self._bitmapSize, self._bitmapSize, color)
|
||||
else:
|
||||
self.fillRect(increaseAxis, staticAxis, self._bitmapSize, self._bitmapSize, color)
|
||||
else:
|
||||
if exchange:
|
||||
self.fillRect(staticAxis, increaseAxis, self._bitmapSize, self._bitmapSize, background)
|
||||
else:
|
||||
self.fillRect(increaseAxis, staticAxis, self._bitmapSize, self._bitmapSize, background)
|
||||
increaseAxis += self._bitmapSize
|
||||
if dataBit & 0x80:
|
||||
i <<= 1
|
||||
else:
|
||||
i >>= 1
|
||||
|
||||
def bitmap(self, x, y, bitmap, w, h, color, background):
|
||||
if w < 0 or h < 0:
|
||||
return
|
||||
x = abs(int(x))
|
||||
y = abs(int(y))
|
||||
|
||||
if self._bmpFmt == self.BITMAP_TBMLLR:
|
||||
oneLineDataLen = (w - 1) // 8 + 1
|
||||
for i in range(h):
|
||||
yMask = y + i * self._bitmapSize
|
||||
self._bitmapHelper(x, yMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x80, False, color, background)
|
||||
elif self._bmpFmt == self.BITMAP_TBMRLL:
|
||||
oneLineDataLen = (w - 1) // 8 + 1
|
||||
for i in range(h):
|
||||
yMask = y + i * self._bitmapSize
|
||||
self._bitmapHelper(x, yMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x01, False, color, background)
|
||||
elif self._bmpFmt == self.BITMAP_BTMLLR:
|
||||
oneLineDataLen = (w - 1) // 8 + 1
|
||||
for i in range(h):
|
||||
yMask = y + h * self._bitmapSize - i * self._bitmapSize
|
||||
self._bitmapHelper(x, yMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x80, False, color, background)
|
||||
elif self._bmpFmt == self.BITMAP_BTMRLL:
|
||||
oneLineDataLen = (w - 1) // 8 + 1
|
||||
for i in range(h):
|
||||
yMask = y + h * self._bitmapSize - i * self._bitmapSize
|
||||
self._bitmapHelper(x, yMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x01, False, color, background)
|
||||
elif self._bmpFmt == self.BITMAP_LRMTLB:
|
||||
oneLineDataLen = (h - 1) // 8 + 1
|
||||
for i in range(w):
|
||||
xMask = x + i * self._bitmapSize
|
||||
self._bitmapHelper(y, xMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x80, True, color, background)
|
||||
elif self._bmpFmt == self.BITMAP_LRMBLT:
|
||||
oneLineDataLen = (h - 1) // 8 + 1
|
||||
for i in range(w):
|
||||
xMask = x + i * self._bitmapSize
|
||||
self._bitmapHelper(y, xMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x01, True, color, background)
|
||||
elif self._bmpFmt == self.BITMAP_RLMTLB:
|
||||
oneLineDataLen = (h - 1) // 8 + 1
|
||||
for i in range(w):
|
||||
xMask = x + w * self._bitmapSize - i * self._bitmapSize
|
||||
self._bitmapHelper(y, xMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x80, True, color, background)
|
||||
elif self._bmpFmt == self.BIMTAP_RLMBLT:
|
||||
oneLineDataLen = (h - 1) // 8 + 1
|
||||
for i in range(w):
|
||||
xMask = x + w * self._bitmapSize - i * self._bitmapSize
|
||||
self._bitmapHelper(y, xMask, bitmap[i * oneLineDataLen : oneLineDataLen * (i + 1)], 0x01, True, color, background)
|
||||
|
||||
def _bytesToNumber(self, data):
|
||||
r = 0
|
||||
i = len(data)
|
||||
while i > 0:
|
||||
i -= 1
|
||||
r = r << 8 | data[i]
|
||||
return r
|
||||
|
||||
def _getQuads(self, data, count):
|
||||
r = []
|
||||
for i in range(count):
|
||||
r.append(data[i * 4 + 54 : i * 4 + 58])
|
||||
return r
|
||||
|
||||
BITMAP_COMPRESSION_NO = 0
|
||||
BITMAP_COMPRESSION_RLE8 = 1
|
||||
BITMAP_COMPRESSION_RLE4 = 2
|
||||
BITMAP_COMPRESSION_FIELDS = 3
|
||||
|
||||
def startDrawBitmapFile(self, x, y):
|
||||
pass
|
||||
|
||||
def bitmapFileHelper(self, buf):
|
||||
pass
|
||||
|
||||
def endDrawBitmapFile(self):
|
||||
pass
|
||||
|
||||
def bitmapFile(self, x, y, path):
|
||||
try:
|
||||
f = open(path, "rb")
|
||||
except:
|
||||
print("open file error")
|
||||
return
|
||||
c = bytearray(f.read())
|
||||
f.close()
|
||||
if c[0] != 0x42 and c[1] != 0x4d:
|
||||
print("file error")
|
||||
print(c[0])
|
||||
print(c[1])
|
||||
return
|
||||
DIBOffset = self._bytesToNumber(c[10:14])
|
||||
width = self._bytesToNumber(c[18:22])
|
||||
height = self._bytesToNumber(c[22:26])
|
||||
colorBits = self._bytesToNumber(c[28:30])
|
||||
compression = self._bytesToNumber(c[30:32])
|
||||
# print("w: %d, h: %d, colorBits: %d" %(width, height, colorBits))
|
||||
|
||||
if colorBits == 24:
|
||||
width3 = width * 3
|
||||
for i in range(height):
|
||||
self.startDrawBitmapFile(x, y + height - i)
|
||||
buf = []
|
||||
left = DIBOffset + i * width3
|
||||
i = 0
|
||||
while i < width3:
|
||||
buf.append(c[left + i + 2])
|
||||
buf.append(c[left + i + 1])
|
||||
buf.append(c[left + i + 0])
|
||||
i += 3
|
||||
self.bitmapFileHelper(buf)
|
||||
self.endDrawBitmapFile()
|
||||
|
||||
elif colorBits == 1:
|
||||
quads = self._getQuads(c, 2)
|
||||
addr = DIBOffset
|
||||
if compression == self.BITMAP_COMPRESSION_NO:
|
||||
addrCountComplement = (width // 8 + 1) % 4
|
||||
if addrCountComplement != 0:
|
||||
addrCountComplement = 4 - addrCountComplement
|
||||
for i in range(height):
|
||||
w = width
|
||||
addrCount = 0
|
||||
self.startDrawBitmapFile(x, y + height - i - 1)
|
||||
buf = []
|
||||
while w > 0:
|
||||
d = c[addr + addrCount]
|
||||
addrCount = addrCount + 1
|
||||
j = 8
|
||||
while w > 0 and j > 0:
|
||||
j -= 1
|
||||
quad = d & (0x01 << j)
|
||||
if quad > 0:
|
||||
quad = 1
|
||||
buf.append(quads[quad][2])
|
||||
buf.append(quads[quad][1])
|
||||
buf.append(quads[quad][0])
|
||||
w -= 1
|
||||
self.bitmapFileHelper(buf)
|
||||
addrCount += addrCountComplement
|
||||
addr += addrCount
|
||||
self.endDrawBitmapFile()
|
||||
else:
|
||||
print("dont support this bitmap file format yet")
|
||||
|
||||
def writeOneChar(self, c):
|
||||
if len(c) > 1:
|
||||
c = c[0]
|
||||
(l, width, height, fmt) = self._fonts.getOneCharacter(c)
|
||||
temp = self._bmpFmt
|
||||
self._bmpFmt = fmt
|
||||
ts = self._textSize
|
||||
if ord(c) == ord("\n"):
|
||||
self._textCursorX = 0
|
||||
self._textCursorY += height * ts + self._textIntervalCol
|
||||
elif len(l):
|
||||
temp1 = self._bitmapSize
|
||||
self._bitmapSize = ts
|
||||
self._textCursorX += self._textIntervalRow
|
||||
if self._textCursorX + ts * width > self._width:
|
||||
self.fillRect(self._textCursorX, self._textCursorY, self._width - self._textCursorX, self._fonts._extensionFontsHeight * ts + self._textIntervalCol, self._textBackground)
|
||||
self._textCursorX = self._textIntervalRow
|
||||
self._textCursorY += ts * self._fonts._extensionFontsHeight + self._textIntervalCol
|
||||
self.fillRect(self._textCursorX, self._textCursorY, self._fonts._extensionFontsWidth * ts + self._textIntervalRow, self._fonts._extensionFontsHeight * ts + self._textIntervalCol, self._textBackground)
|
||||
self.bitmap(self._textCursorX, self._textCursorY, l, width, height, self._textColor, self._textBackground)
|
||||
self._textCursorX += ts * width
|
||||
self._bitmapSize = temp1
|
||||
self._bmpFmt = temp
|
Binary file not shown.
@@ -0,0 +1,69 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import json
|
||||
|
||||
class Fonts:
|
||||
|
||||
def __init__(self):
|
||||
self._haveFontsABC = False
|
||||
self._fontsABC = {}
|
||||
self._fontsABCWidth = 0
|
||||
self._fontsABCHeight = 0
|
||||
self._fontsABCFmt = ""
|
||||
|
||||
self._haveExtensionFonts = False
|
||||
self._extensionFontsWidth = 0
|
||||
self._extensionFontsHeight = 0
|
||||
|
||||
self._enableDefaultFonts = True
|
||||
|
||||
def setFontsABC(self, fonts):
|
||||
self._haveFontsABC = True
|
||||
self._fontsABC = fonts.fonts
|
||||
self._fontsABCWidth = fonts.width
|
||||
self._fontsABCHeight = fonts.height
|
||||
self._fontsABCFmt = fonts.fmt
|
||||
|
||||
self._extensionFontsWidth = fonts.width * 2
|
||||
self._extensionFontsHeight = fonts.height * 2
|
||||
|
||||
def setExFonts(self, obj):
|
||||
self._haveExtensionFonts = True
|
||||
self._extensionFonts = obj
|
||||
self._enableDefaultFonts = False
|
||||
|
||||
def setEnableDefaultFonts(self, opt):
|
||||
if opt:
|
||||
self._enableDefaultFonts = True
|
||||
else:
|
||||
self._enableDefaultFonts = False
|
||||
|
||||
def setExFontsFmt(self, width, height):
|
||||
if self._haveExtensionFonts:
|
||||
self._extensionFonts.setFmt(width, height)
|
||||
self._extensionFontsWidth = width
|
||||
self._extensionFontsHeight = height
|
||||
|
||||
def getOneCharacter(self, c):
|
||||
w = 0
|
||||
h = 0
|
||||
fmt = "UNKNOW"
|
||||
rslt = []
|
||||
done = False
|
||||
if self._haveFontsABC and self._enableDefaultFonts:
|
||||
try:
|
||||
rslt = self._fontsABC[c]
|
||||
w = self._fontsABCWidth
|
||||
h = self._fontsABCHeight
|
||||
fmt = self._fontsABCFmt
|
||||
done = True
|
||||
except:
|
||||
# print("try get fonts ABC faild")
|
||||
pass
|
||||
if self._haveExtensionFonts and done == False:
|
||||
try:
|
||||
(rslt, w, h, fmt) = self._extensionFonts.getOne(c)
|
||||
done = True
|
||||
except:
|
||||
print("try get unicode fonts faild: %s" %(c))
|
||||
return (rslt, w, h, fmt)
|
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import sys
|
||||
|
||||
class PrintString:
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def writeOneChar(self, ch):
|
||||
pass
|
||||
|
||||
def printStr(self, c):
|
||||
try:
|
||||
c = str(c)
|
||||
except:
|
||||
return
|
||||
if sys.version_info.major == 2:
|
||||
c = c.decode("utf-8")
|
||||
for i in c:
|
||||
self.writeOneChar(i)
|
||||
|
||||
def printStrLn(self, c):
|
||||
self.printStr(c)
|
||||
self.writeOneChar("\n")
|
Binary file not shown.
250
pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_epaper.py
Normal file
250
pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_epaper.py
Normal file
@@ -0,0 +1,250 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import time
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
import RPi.GPIO as RPIGPIO
|
||||
from .dfrobot_display.dfrobot_display import DFRobot_Display
|
||||
from .display_extension import fonts_8_16 as fonts_ABC
|
||||
|
||||
try:
|
||||
from .spi import SPI
|
||||
from .gpio import GPIO
|
||||
except:
|
||||
print("unknow platform")
|
||||
exit()
|
||||
|
||||
CONFIG_IL0376F = {
|
||||
|
||||
}
|
||||
|
||||
CONFIG_IL3895 = {
|
||||
|
||||
}
|
||||
|
||||
class DFRobot_Epaper(DFRobot_Display):
|
||||
|
||||
XDOT = 128
|
||||
YDOT = 250
|
||||
|
||||
FULL = True
|
||||
PART = False
|
||||
|
||||
def __init__(self, width = 250, height = 122):
|
||||
DFRobot_Display.__init__(self, width, height)
|
||||
# length = width * height // 8
|
||||
length = 4000
|
||||
self._displayBuffer = bytearray(length)
|
||||
i = 0
|
||||
while i < length:
|
||||
self._displayBuffer[i] = 0xff
|
||||
i = i + 1
|
||||
|
||||
self._isBusy = False
|
||||
self._busyExitEdge = GPIO.RISING
|
||||
|
||||
self._fonts.setFontsABC(fonts_ABC)
|
||||
self.setExFontsFmt(16, 16)
|
||||
|
||||
def _busyCB(self, channel):
|
||||
self._isBusy = False
|
||||
|
||||
def setBusyExitEdge(self, edge):
|
||||
if edge != GPIO.HIGH and edge != GPIO.LOW:
|
||||
return
|
||||
self._busyEdge = edge
|
||||
|
||||
def begin(self):
|
||||
pass
|
||||
#self._init()
|
||||
#self._powerOn()
|
||||
#self.setBusyCB(self._busyCB)
|
||||
#self._powerOn()
|
||||
|
||||
def setBuffer(self, buffer):
|
||||
self._displayBuffer = buffer
|
||||
|
||||
def pixel(self, x, y, color):
|
||||
if x < 0 or x >= self._width:
|
||||
return
|
||||
if y < 0 or y >= self._height:
|
||||
return
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
m = int(x * 16 + (y + 1) / 8)
|
||||
sy = int((y + 1) % 8)
|
||||
if color == self.WHITE:
|
||||
if sy != 0:
|
||||
self._displayBuffer[m] = self._displayBuffer[m] | int(pow(2, 8 - sy))
|
||||
else:
|
||||
self._displayBuffer[m - 1] = self._displayBuffer[m - 1] | 1
|
||||
elif color == self.BLACK:
|
||||
if sy != 0:
|
||||
self._displayBuffer[m] = self._displayBuffer[m] & (0xff - int(pow(2, 8 - sy)))
|
||||
else:
|
||||
self._displayBuffer[m - 1] = self._displayBuffer[m - 1] & 0xfe
|
||||
|
||||
def _initLut(self, mode):
|
||||
if mode == self.FULL:
|
||||
self.writeCmdAndData(0x32, [ 0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x0F, 0x0F, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x0F, 0x00, 0x00, 0x03,
|
||||
0x0F, 0x0F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
])
|
||||
elif mode == self.PART:
|
||||
self.writeCmdAndData(0x32, [0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x50, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
|
||||
0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x0f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
])
|
||||
|
||||
def _setRamData(self, xStart, xEnd, yStart, yStart1, yEnd, yEnd1):
|
||||
self.writeCmdAndData(0x44, [xStart, xEnd])
|
||||
self.writeCmdAndData(0x45, [yStart, yStart1, yEnd, yEnd1])
|
||||
|
||||
def _setRamPointer(self, x, y, y1):
|
||||
self.writeCmdAndData(0x4e, [x])
|
||||
self.writeCmdAndData(0x4f, [y, y1])
|
||||
|
||||
def _init(self,mode):
|
||||
self.writeCmdAndData(0x12, [])
|
||||
self.writeCmdAndData(0x01, [0xf9, 0x00, 0x00])
|
||||
self.writeCmdAndData(0x74, [0x54])
|
||||
self.writeCmdAndData(0x7e, [0x3b])
|
||||
self.writeCmdAndData(0x11, [0x01])
|
||||
self._setRamData(0x00, 0x0f, 0xf9,0x00, 0x00, 0x00)
|
||||
self.writeCmdAndData(0x3c, [0x03])
|
||||
self._setRamPointer(0x00, 0xf9, 0x00)
|
||||
self.writeCmdAndData(0x21, [0x08])
|
||||
self.writeCmdAndData(0x2c, [0x50])
|
||||
self.writeCmdAndData(0x03, [0x15])
|
||||
self.writeCmdAndData(0x04, [0x41,0xa8,0x32])
|
||||
self.writeCmdAndData(0x3a, [0x2c])
|
||||
self.writeCmdAndData(0x3b, [0x0b])
|
||||
self.writeCmdAndData(0x0c, [0x8b,0x9c,0x96,0x0f])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _writeDisRam(self, sizeX, sizeY):
|
||||
if sizeX % 8 != 0:
|
||||
sizeX = sizeX + (8 - sizeX % 8)
|
||||
sizeX = sizeX // 8
|
||||
|
||||
self.writeCmdAndData(0x24, self._displayBuffer[0: sizeX * sizeY])
|
||||
|
||||
|
||||
|
||||
def _updateDis(self, mode):
|
||||
if mode == self.FULL:
|
||||
self.writeCmdAndData(0x22, [0xc7])
|
||||
elif mode == self.PART:
|
||||
self.writeCmdAndData(0x22, [0xc7])
|
||||
else:
|
||||
return
|
||||
self.writeCmdAndData(0x20, [])
|
||||
|
||||
|
||||
def _waitBusyExit(self):
|
||||
temp = 0
|
||||
while self.readBusy() != False:
|
||||
time.sleep(0.01)
|
||||
temp = temp + 1
|
||||
if (temp % 200) == 0:
|
||||
print("waitBusyExit")
|
||||
|
||||
def _powerOn(self):
|
||||
self.writeCmdAndData(0x22, [0xC0])
|
||||
self.writeCmdAndData(0x20, [])
|
||||
|
||||
def _powerOff(self):
|
||||
self.writeCmdAndData(0x10, [0x01])
|
||||
time.sleep(0.1)
|
||||
|
||||
def _disPart(self, xStart, xEnd, yStart, yEnd):
|
||||
self._setRamData(xStart // 8, xEnd // 8, yEnd % 256, yEnd // 256, yStart % 256, yStart // 256)
|
||||
self._setRamPointer(xStart // 8, yEnd % 256, yEnd // 256)
|
||||
self._writeDisRam(xEnd - xStart, yEnd - yStart + 1)
|
||||
self._updateDis(self.PART)
|
||||
|
||||
def flush(self, mode):
|
||||
if mode != self.FULL and mode != self.PART:
|
||||
return
|
||||
self._init(mode)
|
||||
self._initLut(mode)
|
||||
self._powerOn()
|
||||
if mode == self.PART:
|
||||
self._disPart(0, self.XDOT - 1, 0, self.YDOT - 1)
|
||||
else:
|
||||
self._setRamPointer(0x00, (self.YDOT - 1) % 256, (self.YDOT - 1) // 256)
|
||||
self._writeDisRam(self.XDOT, self.YDOT)
|
||||
self._updateDis(self.FULL)
|
||||
|
||||
def startDrawBitmapFile(self, x, y):
|
||||
self._bitmapFileStartX = x
|
||||
self._bitmapFileStartY = y
|
||||
|
||||
def bitmapFileHelper(self, buf):
|
||||
for i in range(len(buf) // 3):
|
||||
addr = i * 3
|
||||
if buf[addr] == 0x00 and buf[addr + 1] == 0x00 and buf[addr + 2] == 0x00:
|
||||
self.pixel(self._bitmapFileStartX, self._bitmapFileStartY, self.BLACK)
|
||||
else:
|
||||
self.pixel(self._bitmapFileStartX, self._bitmapFileStartY, self.WHITE)
|
||||
self._bitmapFileStartX += 1
|
||||
|
||||
def endDrawBitmapFile(self):
|
||||
self.flush(self.PART)
|
||||
|
||||
class DFRobot_Epaper_SPI(DFRobot_Epaper):
|
||||
|
||||
def __init__(self, bus, dev, cs, cd, busy):
|
||||
DFRobot_Epaper.__init__(self)
|
||||
self._spi = SPI(bus, dev)
|
||||
self._cs = GPIO(cs, GPIO.OUT)
|
||||
self._cd = GPIO(cd, GPIO.OUT)
|
||||
self._busy = GPIO(busy, GPIO.IN)
|
||||
|
||||
def writeCmdAndData(self, cmd, data = []):
|
||||
self._waitBusyExit()
|
||||
self._cs.setOut(GPIO.LOW)
|
||||
self._cd.setOut(GPIO.LOW)
|
||||
self._spi.transfer([cmd])
|
||||
self._cd.setOut(GPIO.HIGH)
|
||||
self._spi.transfer(data)
|
||||
self._cs.setOut(GPIO.HIGH)
|
||||
|
||||
def readBusy(self):
|
||||
return self._busy.read()
|
||||
|
||||
def setBusyCB(self, cb):
|
||||
self._busy.setInterrupt(self._busyExitEdge, cb)
|
||||
def __del__(self):
|
||||
RPIGPIO.cleanup()
|
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/__init__.pyc
Normal file
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/__init__.pyc
Normal file
Binary file not shown.
101
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/fonts_6_8.py
Normal file
101
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/fonts_6_8.py
Normal file
@@ -0,0 +1,101 @@
|
||||
fonts = { # left to right, msb to bottom, lsb to top
|
||||
" ": [0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
"!": [0x00,0x00,0x5F,0x00,0x00,0x00],
|
||||
"\"": [0x00,0x07,0x00,0x07,0x00,0x00],
|
||||
"#": [0x14,0x7F,0x14,0x7F,0x14,0x00],
|
||||
"$": [0x24,0x2A,0x7F,0x2A,0x12,0x00],
|
||||
"%": [0x23,0x13,0x08,0x64,0x62,0x00],
|
||||
"&": [0x36,0x49,0x56,0x20,0x50,0x00],
|
||||
"'": [0x00,0x08,0x07,0x03,0x00,0x00],
|
||||
"(": [0x00,0x1C,0x22,0x41,0x00,0x00],
|
||||
")": [0x00,0x41,0x22,0x1C,0x00,0x00],
|
||||
"*": [0x24,0x18,0x7E,0x18,0x24,0x00],
|
||||
"+": [0x08,0x08,0x3E,0x08,0x08,0x00],
|
||||
",": [0x00,0x80,0x70,0x30,0x00,0x00],
|
||||
"-": [0x08,0x08,0x08,0x08,0x08,0x00],
|
||||
".": [0x00,0x00,0x60,0x60,0x00,0x00],
|
||||
"/": [0x20,0x10,0x08,0x04,0x02,0x00],
|
||||
"0": [0x3E,0x41,0x49,0x41,0x3E,0x00],
|
||||
"1": [0x00,0x42,0x7F,0x40,0x00,0x00],
|
||||
"2": [0x72,0x49,0x49,0x49,0x46,0x00],
|
||||
"3": [0x21,0x41,0x49,0x4D,0x32,0x00],
|
||||
"4": [0x18,0x14,0x12,0x7F,0x10,0x00],
|
||||
"5": [0x27,0x45,0x45,0x45,0x38,0x00],
|
||||
"6": [0x3C,0x4A,0x49,0x49,0x31,0x00],
|
||||
"7": [0x41,0x21,0x11,0x09,0x07,0x00],
|
||||
"8": [0x36,0x49,0x49,0x49,0x36,0x00],
|
||||
"9": [0x46,0x49,0x49,0x29,0x16,0x00],
|
||||
":": [0x00,0x00,0x14,0x00,0x00,0x00],
|
||||
";": [0x00,0x40,0x34,0x00,0x00,0x00],
|
||||
"<": [0x00,0x08,0x14,0x22,0x41,0x00],
|
||||
"=": [0x14,0x14,0x14,0x14,0x14,0x00],
|
||||
">": [0x00,0x41,0x22,0x14,0x08,0x00],
|
||||
"?": [0x02,0x01,0x59,0x09,0x06,0x00],
|
||||
"@": [0x3E,0x41,0x5D,0x59,0x4E,0x00],
|
||||
"A": [0x7C,0x12,0x11,0x12,0x7C,0x00],
|
||||
"B": [0x7F,0x49,0x49,0x49,0x36,0x00],
|
||||
"C": [0x3E,0x41,0x41,0x41,0x22,0x00],
|
||||
"D": [0x7F,0x41,0x41,0x41,0x3E,0x00],
|
||||
"E": [0x7F,0x49,0x49,0x49,0x41,0x00],
|
||||
"F": [0x7F,0x09,0x09,0x09,0x01,0x00],
|
||||
"G": [0x3E,0x41,0x41,0x51,0x73,0x00],
|
||||
"H": [0x7F,0x08,0x08,0x08,0x7F,0x00],
|
||||
"I": [0x00,0x41,0x7F,0x41,0x00,0x00],
|
||||
"J": [0x20,0x40,0x41,0x3F,0x01,0x00],
|
||||
"K": [0x7F,0x08,0x14,0x22,0x41,0x00],
|
||||
"L": [0x7F,0x40,0x40,0x40,0x40,0x00],
|
||||
"M": [0x7F,0x02,0x1C,0x02,0x7F,0x00],
|
||||
"N": [0x7F,0x04,0x08,0x10,0x7F,0x00],
|
||||
"O": [0x3E,0x41,0x41,0x41,0x3E,0x00],
|
||||
"P": [0x7F,0x09,0x09,0x09,0x06,0x00],
|
||||
"Q": [0x3E,0x41,0x51,0x21,0x5E,0x00],
|
||||
"R": [0x7F,0x09,0x19,0x29,0x46,0x00],
|
||||
"S": [0x26,0x49,0x49,0x49,0x32,0x00],
|
||||
"T": [0x03,0x01,0x7F,0x01,0x03,0x00],
|
||||
"U": [0x3F,0x40,0x40,0x40,0x3F,0x00],
|
||||
"V": [0x1F,0x20,0x40,0x20,0x1F,0x00],
|
||||
"W": [0x3F,0x40,0x38,0x40,0x3F,0x00],
|
||||
"X": [0x63,0x14,0x08,0x14,0x63,0x00],
|
||||
"Y": [0x03,0x04,0x78,0x04,0x03,0x00],
|
||||
"Z": [0x61,0x59,0x49,0x4D,0x43,0x00],
|
||||
"[": [0x00,0x7F,0x41,0x41,0x41,0x00],
|
||||
"\\": [0x02,0x04,0x08,0x10,0x20,0x00],
|
||||
"]": [0x00,0x41,0x41,0x41,0x7f,0x00],
|
||||
"^": [0x04,0x02,0x01,0x02,0x04,0x00],
|
||||
"_": [0x40,0x40,0x40,0x40,0x46,0x00],
|
||||
"'": [0x00,0x03,0x07,0x08,0x00,0x00],
|
||||
"a": [0x20,0x54,0x54,0x78,0x40,0x00],
|
||||
"b": [0x7F,0x28,0x44,0x44,0x38,0x00],
|
||||
"c": [0x38,0x44,0x44,0x44,0x28,0x00],
|
||||
"d": [0x38,0x44,0x44,0x28,0x7F,0x00],
|
||||
"e": [0x38,0x54,0x54,0x54,0x18,0x00],
|
||||
"f": [0x00,0x08,0x7E,0x09,0x02,0x00],
|
||||
"g": [0x38,0xA4,0xA4,0x9C,0x78,0x00],
|
||||
"h": [0x7F,0x08,0x04,0x04,0x78,0x00],
|
||||
"i": [0x00,0x44,0x7D,0x40,0x00,0x00],
|
||||
"j": [0x20,0x40,0x40,0x3D,0x00,0x00],
|
||||
"k": [0x7F,0x10,0x28,0x44,0x00,0x00],
|
||||
"l": [0x00,0x41,0x7F,0x40,0x00,0x00],
|
||||
"m": [0x7C,0x04,0x78,0x04,0x78,0x00],
|
||||
"n": [0x7C,0x08,0x04,0x04,0x78,0x00],
|
||||
"o": [0x38,0x44,0x44,0x44,0x38,0x00],
|
||||
"p": [0xFC,0x18,0x24,0x24,0x18,0x00],
|
||||
"q": [0x18,0x24,0x24,0x18,0xFC,0x00],
|
||||
"r": [0x7C,0x08,0x04,0x04,0x08,0x00],
|
||||
"s": [0x48,0x54,0x54,0x54,0x24,0x00],
|
||||
"t": [0x04,0x04,0x3F,0x44,0x24,0x00],
|
||||
"u": [0x3C,0x40,0x40,0x20,0x7C,0x00],
|
||||
"v": [0x1C,0x20,0x40,0x20,0x1C,0x00],
|
||||
"w": [0x3C,0x40,0x20,0x40,0x3C,0x00],
|
||||
"x": [0x44,0x28,0x10,0x28,0x44,0x00],
|
||||
"y": [0x4C,0x90,0x90,0x90,0x7C,0x00],
|
||||
"z": [0x44,0x64,0x54,0x4C,0x44,0x00],
|
||||
"{": [0x00,0x08,0x36,0x41,0x00,0x00],
|
||||
"|": [0x00,0x00,0x77,0x00,0x00,0x00],
|
||||
"}": [0x00,0x41,0x36,0x08,0x00,0x00],
|
||||
"~": [0x02,0x01,0x02,0x04,0x02,0x00]
|
||||
}
|
||||
|
||||
width = 6
|
||||
height = 8
|
||||
fmt = "LRMBLT"
|
101
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/fonts_8_16.py
Normal file
101
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/fonts_8_16.py
Normal file
@@ -0,0 +1,101 @@
|
||||
fonts = { # top to bottom, msb left, lsb right
|
||||
" ": [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
"!": [0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00],
|
||||
"\"": [0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
"#": [0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00],
|
||||
"$": [0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00],
|
||||
"%": [0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00],
|
||||
"&": [0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00],
|
||||
"'": [0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
"(": [0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00],
|
||||
")": [0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00],
|
||||
"*": [0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00],
|
||||
"+": [0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00],
|
||||
",": [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00],
|
||||
"-": [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
".": [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00],
|
||||
"/": [0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00],
|
||||
"0": [0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"1": [0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00],
|
||||
"2": [0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00],
|
||||
"3": [0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"4": [0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00],
|
||||
"5": [0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00],
|
||||
"6": [0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"7": [0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00],
|
||||
"8": [0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"9": [0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00],
|
||||
":": [0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00],
|
||||
";": [0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00],
|
||||
"<": [0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00],
|
||||
"=": [0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
">": [0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00],
|
||||
"?": [0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00],
|
||||
"@": [0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00],
|
||||
"A": [0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00],
|
||||
"B": [0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00],
|
||||
"C": [0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00],
|
||||
"D": [0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00],
|
||||
"E": [0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00],
|
||||
"F": [0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00],
|
||||
"G": [0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00],
|
||||
"H": [0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00],
|
||||
"I": [0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00],
|
||||
"J": [0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00],
|
||||
"K": [0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00],
|
||||
"L": [0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00],
|
||||
"M": [0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00],
|
||||
"N": [0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00],
|
||||
"O": [0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00],
|
||||
"P": [0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00],
|
||||
"Q": [0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00],
|
||||
"R": [0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00],
|
||||
"S": [0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"T": [0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00],
|
||||
"U": [0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"V": [0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00],
|
||||
"W": [0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00],
|
||||
"X": [0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00],
|
||||
"Y": [0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00],
|
||||
"Z": [0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00],
|
||||
"[": [0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00],
|
||||
"\\": [0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00],
|
||||
"]": [0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00],
|
||||
"^": [0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
"_": [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00],
|
||||
"'": [0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
|
||||
"a": [0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00],
|
||||
"b": [0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00],
|
||||
"c": [0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"d": [0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00],
|
||||
"e": [0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"f": [0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00],
|
||||
"g": [0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00],
|
||||
"h": [0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00],
|
||||
"i": [0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00],
|
||||
"j": [0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00],
|
||||
"k": [0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00],
|
||||
"l": [0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00],
|
||||
"m": [0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00],
|
||||
"n": [0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00],
|
||||
"o": [0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"p": [0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00],
|
||||
"q": [0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00],
|
||||
"r": [0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00],
|
||||
"s": [0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00],
|
||||
"t": [0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00],
|
||||
"u": [0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00],
|
||||
"v": [0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00],
|
||||
"w": [0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00],
|
||||
"x": [0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00],
|
||||
"y": [0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00],
|
||||
"z": [0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00],
|
||||
"{": [0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00],
|
||||
"|": [0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00],
|
||||
"}": [0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00],
|
||||
"~": [0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
|
||||
}
|
||||
|
||||
width = 8
|
||||
height = 16
|
||||
fmt = "TBMLLR"
|
Binary file not shown.
@@ -0,0 +1,80 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
'''
|
||||
depends: freetype-py
|
||||
'''
|
||||
|
||||
import freetype
|
||||
import math
|
||||
#import sys
|
||||
|
||||
#reload(sys)
|
||||
#sys.setdefaultencoding("utf-8")
|
||||
import importlib,sys
|
||||
|
||||
#importlib.reload(sys)
|
||||
class Freetype_Helper:
|
||||
|
||||
def __init__(self, filePath):
|
||||
self._face = freetype.Face(filePath)
|
||||
self._width = 0
|
||||
self._height = 0
|
||||
self._fade = 96
|
||||
|
||||
def setFmt(self, width, height):
|
||||
self._width = int(width)
|
||||
self._height = int(height)
|
||||
self._face.set_pixel_sizes(width, height)
|
||||
|
||||
def setDisLowerLimite(self, limite):
|
||||
self._fade = limite
|
||||
|
||||
def getOne(self, ch):
|
||||
self._face.load_char(ch)
|
||||
bitmap = self._face.glyph.bitmap
|
||||
originY = self._face.glyph.bitmap_top
|
||||
width = bitmap.width
|
||||
height = bitmap.rows
|
||||
buffer = bitmap.buffer
|
||||
rslt = []
|
||||
|
||||
# width = 4
|
||||
# height = 4
|
||||
# buffer = [0xff] * width * height
|
||||
|
||||
if height > self._height:
|
||||
buffer = buffer[0: width * self._height]
|
||||
height = self._height
|
||||
if width > self._width:
|
||||
for i in range(height):
|
||||
rslt += buffer[i * width: i * width + self._width]
|
||||
width = self._width
|
||||
buffer = rslt
|
||||
rslt = []
|
||||
if (ord(ch) >= ord(" ") and ord(ch) <= ord("~")) or width <= (self._width // 2):
|
||||
rslt = [0] * (((self._width - 1) // 16 + 1) * self._height + 1)
|
||||
left = (self._width // 2 - width) // 2
|
||||
lineDataLen = (self._width - 1) // 16 + 1
|
||||
else:
|
||||
rslt = [0] * (((self._width - 1) // 8 + 1) * self._height + 1)
|
||||
left = (self._width - width) // 2
|
||||
lineDataLen = (self._width - 1) // 8 + 1
|
||||
if left < 0:
|
||||
left = 0
|
||||
# top = (self._height - height) * lineDataLen // 2
|
||||
top = ((self._height * 8 + 5) // 10 - originY) * lineDataLen
|
||||
if top < 0:
|
||||
top = 0
|
||||
for i in range(height):
|
||||
for j in range(width):
|
||||
if buffer[i * width + j] > self._fade:
|
||||
try:
|
||||
rslt[i * lineDataLen + (j + left) // 8 + top] |= 0x80 >> ((j + left) % 8)
|
||||
except:
|
||||
print("freetype_helper getOne err: width: %d, height: %d, top: %d, left: %d, rslt_len: %d, originY: %d" %(width, height, top, left, len(rslt), originY))
|
||||
raise("err")
|
||||
# rslt[i * lineDataLen + (j + left) // 8 + top] |= 0x80 >> ((j + left) % 8)
|
||||
if (ord(ch) >= ord(" ") and ord(ch) <= ord("~")) or width < (self._width // 2):
|
||||
return (rslt, self._width // 2, self._height, "TBMLLR")
|
||||
else:
|
||||
return (rslt, self._width, self._height, "TBMLLR")
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,2 @@
|
||||
wqydkzh.ttf = 文泉驿等宽正黑.ttf GPL2 license </br>
|
||||
zkklt.ttf = 站酷快乐体.ttf Chinese open source fonts file, use with freetype_helper.py
|
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/wqydkzh.ttf
Normal file
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/wqydkzh.ttf
Normal file
Binary file not shown.
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/zkklt.ttf
Normal file
BIN
pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/zkklt.ttf
Normal file
Binary file not shown.
64
pwnagotchi/ui/hw/libs/dfrobot/v2/gpio.py
Normal file
64
pwnagotchi/ui/hw/libs/dfrobot/v2/gpio.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import time
|
||||
import RPi.GPIO as RPIGPIO
|
||||
|
||||
RPIGPIO.setmode(RPIGPIO.BCM)
|
||||
RPIGPIO.setwarnings(False)
|
||||
|
||||
class GPIO:
|
||||
|
||||
HIGH = RPIGPIO.HIGH
|
||||
LOW = RPIGPIO.LOW
|
||||
|
||||
OUT = RPIGPIO.OUT
|
||||
IN = RPIGPIO.IN
|
||||
|
||||
RISING = RPIGPIO.RISING
|
||||
FALLING = RPIGPIO.FALLING
|
||||
BOTH = RPIGPIO.BOTH
|
||||
|
||||
def __init__(self, pin, mode, defaultOut = HIGH):
|
||||
self._pin = pin
|
||||
self._fInt = None
|
||||
self._intDone = True
|
||||
self._intMode = None
|
||||
if mode == self.OUT:
|
||||
RPIGPIO.setup(pin, mode)
|
||||
if defaultOut == self.HIGH:
|
||||
RPIGPIO.output(pin, defaultOut)
|
||||
else:
|
||||
RPIGPIO.output(pin, self.LOW)
|
||||
else:
|
||||
RPIGPIO.setup(pin, self.IN, pull_up_down = RPIGPIO.PUD_UP)
|
||||
|
||||
def setOut(self, level):
|
||||
if level:
|
||||
RPIGPIO.output(self._pin, self.HIGH)
|
||||
else:
|
||||
RPIGPIO.output(self._pin, self.LOW)
|
||||
|
||||
def _intCB(self, status):
|
||||
if self._intDone:
|
||||
self._intDone = False
|
||||
time.sleep(0.02)
|
||||
if self._intMode == self.BOTH:
|
||||
self._fInt()
|
||||
elif self._intMode == self.RISING and self.read() == self.HIGH:
|
||||
self._fInt()
|
||||
elif self._intMode == self.FALLING and self.read() == self.LOW:
|
||||
self._fInt()
|
||||
self._intDone = True
|
||||
|
||||
def setInterrupt(self, mode, cb):
|
||||
if mode != self.RISING and mode != self.FALLING and mode != self.BOTH:
|
||||
return
|
||||
self._intMode = mode
|
||||
RPIGPIO.add_event_detect(self._pin, mode, self._intCB)
|
||||
self._fInt = cb
|
||||
|
||||
def read(self):
|
||||
return RPIGPIO.input(self._pin)
|
||||
|
||||
def cleanup(self):
|
||||
RPIGPIO.cleanup()
|
21
pwnagotchi/ui/hw/libs/dfrobot/v2/i2c.py
Normal file
21
pwnagotchi/ui/hw/libs/dfrobot/v2/i2c.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
'''
|
||||
change i2c frequency on raspberry:
|
||||
1. edit /etc/modprobe.d
|
||||
2. add line:
|
||||
options i2c_bcm2708 baudrate=400000
|
||||
'''
|
||||
|
||||
import smbus
|
||||
|
||||
class I2C:
|
||||
|
||||
def __init__(self, port):
|
||||
self._bus = smbus.SMBus(port)
|
||||
|
||||
def writeBytes(self, addr, reg, buf):
|
||||
self._bus.write_block_data(addr, reg, buf)
|
||||
|
||||
def readBytes(self, addr, reg, length):
|
||||
return self._bus.read_block_data(addr, reg, length)
|
21
pwnagotchi/ui/hw/libs/dfrobot/v2/spi.py
Normal file
21
pwnagotchi/ui/hw/libs/dfrobot/v2/spi.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import spidev
|
||||
|
||||
class SPI:
|
||||
|
||||
MODE_1 = 1
|
||||
MODE_2 = 2
|
||||
MODE_3 = 3
|
||||
MODE_4 = 4
|
||||
|
||||
def __init__(self, bus, dev, speed = 3900000, mode = MODE_4):
|
||||
self._bus = spidev.SpiDev()
|
||||
self._bus.open(0, 0)
|
||||
self._bus.no_cs = True
|
||||
self._bus.max_speed_hz = speed
|
||||
|
||||
def transfer(self, buf):
|
||||
if len(buf):
|
||||
return self._bus.xfer(buf)
|
||||
return []
|
@@ -1,20 +1,20 @@
|
||||
import _thread
|
||||
from threading import Lock
|
||||
import time
|
||||
import logging
|
||||
import random
|
||||
import time
|
||||
from threading import Lock
|
||||
|
||||
from PIL import ImageDraw
|
||||
|
||||
import pwnagotchi
|
||||
import pwnagotchi.utils as utils
|
||||
import pwnagotchi.plugins as plugins
|
||||
from pwnagotchi.voice import Voice
|
||||
|
||||
import pwnagotchi.ui.web as web
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
import pwnagotchi.ui.faces as faces
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
import pwnagotchi.ui.web as web
|
||||
import pwnagotchi.utils as utils
|
||||
from pwnagotchi.ui.components import *
|
||||
from pwnagotchi.ui.state import State
|
||||
from pwnagotchi.voice import Voice
|
||||
|
||||
WHITE = 0xff
|
||||
BLACK = 0x00
|
||||
@@ -345,6 +345,11 @@ class View(object):
|
||||
self.update()
|
||||
time.sleep(5.0)
|
||||
|
||||
def on_uploading(self, to):
|
||||
self.set('face', random.choice((faces.UPLOAD, faces.UPLOAD1, faces.UPLOAD2)))
|
||||
self.set('status', self._voice.on_uploading(to))
|
||||
self.update(force=True)
|
||||
|
||||
def on_rebooting(self):
|
||||
self.set('face', faces.BROKEN)
|
||||
self.set('status', self._voice.on_rebooting())
|
||||
|
@@ -5,6 +5,37 @@
|
||||
Plugins
|
||||
{% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
{{ super() }}
|
||||
<style>
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
.tooltip .tooltiptext {
|
||||
visibility: hidden;
|
||||
width: 200px;
|
||||
background-color: #3388cc;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 10px;
|
||||
border: 2px solid black;
|
||||
padding: 20px 0;
|
||||
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -100px;
|
||||
}
|
||||
|
||||
.tooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
$(function(){
|
||||
$('input[type=checkbox]').change(function(e) {
|
||||
@@ -27,11 +58,19 @@ $(function(){
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="container">
|
||||
{% for name in database.keys() %}
|
||||
{% for name in database.keys() | sort %}
|
||||
{% set has_info = name in loaded and loaded[name].__description__ is defined %}
|
||||
<div class="plugins-box">
|
||||
<h4>
|
||||
<a {% if name in loaded and loaded[name].on_webhook is defined %} href="/plugins/{{name}}" {% endif %}>{{name}}</a>
|
||||
</h4>
|
||||
<div class="tooltip">
|
||||
<h4>
|
||||
<a {% if name in loaded and loaded[name].on_webhook is defined %} href="/plugins/{{name}}" {% endif %}>{{name}}</a>
|
||||
</h4>
|
||||
{% if has_info %}
|
||||
<span class="tooltiptext">{{ loaded[name].__description__ }}</span>
|
||||
{% else %}
|
||||
<span class="tooltiptext">Description can't be loaded yet.</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<form method="POST" action="/plugins/toggle">
|
||||
<input type="checkbox" data-role="flipswitch" name="enabled" id="flip-checkbox-{{name}}" data-on-text="Enabled" data-off-text="Disabled" data-wrapper-class="custom-size-flipswitch" {% if name in loaded %} checked {% endif %}>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
|
@@ -257,8 +257,11 @@ def load_config(args):
|
||||
elif config['ui']['display']['type'] in ('lcdhat',):
|
||||
config['ui']['display']['type'] = 'lcdhat'
|
||||
|
||||
elif config['ui']['display']['type'] in ('dfrobot', 'df'):
|
||||
config['ui']['display']['type'] = 'dfrobot'
|
||||
elif config['ui']['display']['type'] in ('dfrobot_1', 'df1'):
|
||||
config['ui']['display']['type'] = 'dfrobot_1'
|
||||
|
||||
elif config['ui']['display']['type'] in ('dfrobot_2', 'df2'):
|
||||
config['ui']['display']['type'] = 'dfrobot_2'
|
||||
|
||||
elif config['ui']['display']['type'] in ('ws_154inch', 'ws154inch', 'waveshare_154inch', 'waveshare154inch'):
|
||||
config['ui']['display']['type'] = 'waveshare154inch'
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import random
|
||||
import gettext
|
||||
import os
|
||||
import random
|
||||
|
||||
|
||||
class Voice:
|
||||
@@ -159,6 +159,9 @@ class Voice:
|
||||
def on_rebooting(self):
|
||||
return self._("Oops, something went wrong ... Rebooting ...")
|
||||
|
||||
def on_uploading(self, to):
|
||||
return self._("Uploading data to {to} ...").format(to=to)
|
||||
|
||||
def on_last_session_data(self, last_session):
|
||||
status = self._('Kicked {num} stations\n').format(num=last_session.deauthed)
|
||||
if last_session.associated > 999:
|
||||
|
7
release.stork
Executable file
7
release.stork
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env stork -f
|
||||
|
||||
version:parser "__version__\\s*=\\s*['\"]([\\d\\.ab]+)[\"']"
|
||||
version:file "pwnagotchi/_version.py"
|
||||
version:from_user
|
||||
|
||||
git:create_tag $VERSION
|
@@ -1,57 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
NEW=()
|
||||
FIXES=()
|
||||
MISC=()
|
||||
|
||||
echo "@ Fetching remote tags ..."
|
||||
git fetch --tags >/dev/null
|
||||
printf "\n\n"
|
||||
|
||||
CURTAG=$(git describe --tags --abbrev=0)
|
||||
OUTPUT=$(git log $CURTAG..HEAD --oneline)
|
||||
IFS=$'\n' LINES=($OUTPUT)
|
||||
|
||||
for LINE in "${LINES[@]}"; do
|
||||
LINE=$(echo "$LINE" | sed -E "s/^[[:xdigit:]]+\s+//")
|
||||
if [[ $LINE == *"new:"* ]]; then
|
||||
LINE=$(echo "$LINE" | sed -E "s/^new: //")
|
||||
NEW+=("$LINE")
|
||||
elif [[ $LINE == *"fix:"* ]]; then
|
||||
LINE=$(echo "$LINE" | sed -E "s/^fix: //")
|
||||
FIXES+=("$LINE")
|
||||
elif [[ $LINE != *"i did not bother commenting"* ]] && [[ $LINE != *"Merge "* ]]; then
|
||||
echo " MISC LINE =$LINE"
|
||||
LINE=$(echo "$LINE" | sed -E "s/^[a-z]+: //")
|
||||
MISC+=("$LINE")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$NEW" ]; then
|
||||
echo
|
||||
echo "**New Features**"
|
||||
echo
|
||||
for l in "${NEW[@]}"; do
|
||||
echo "* $l"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$FIXES" ]; then
|
||||
echo
|
||||
echo "**Fixes**"
|
||||
echo
|
||||
for l in "${FIXES[@]}"; do
|
||||
echo "* $l"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$MISC" ]; then
|
||||
echo
|
||||
echo "**Misc**"
|
||||
echo
|
||||
for l in "${MISC[@]}"; do
|
||||
echo "* $l"
|
||||
done
|
||||
fi
|
||||
|
||||
echo
|
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# name of the ethernet gadget interface on the host
|
||||
USB_IFACE=${1:-enp0s20f0u1}
|
||||
|
@@ -1,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
# nothing to see here, just a utility i use to create new releases ^_^
|
||||
|
||||
VERSION_FILE=$(dirname "${BASH_SOURCE[0]}")/../pwnagotchi/_version.py
|
||||
echo "version file is $VERSION_FILE"
|
||||
CURRENT_VERSION=$(cat $VERSION_FILE | grep version | cut -d"'" -f2)
|
||||
TO_UPDATE=(
|
||||
$VERSION_FILE
|
||||
)
|
||||
|
||||
echo -n "current version is $CURRENT_VERSION, select new version: "
|
||||
read NEW_VERSION
|
||||
echo "creating version $NEW_VERSION ...\n"
|
||||
|
||||
for file in "${TO_UPDATE[@]}"; do
|
||||
echo "patching $file ..."
|
||||
sed -i.bak "s/$CURRENT_VERSION/$NEW_VERSION/g" "$file"
|
||||
rm -rf "$file.bak"
|
||||
git add $file
|
||||
done
|
||||
|
||||
git commit -m "releasing v$NEW_VERSION"
|
||||
git push
|
||||
git tag -a v$NEW_VERSION -m "release v$NEW_VERSION"
|
||||
git push origin v$NEW_VERSION
|
||||
|
||||
echo
|
||||
echo "All done, v$NEW_VERSION released ^_^"
|
@@ -20,6 +20,7 @@ while getopts "hb:n:u:" arg; do
|
||||
UNIT_USERNAME=$OPTARG
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
esac
|
||||
done
|
||||
|
Reference in New Issue
Block a user