new: integrated python standard logger (closes #84)
This commit is contained in:
parent
335e6b1311
commit
4cf2866737
@ -202,14 +202,14 @@ running = False
|
||||
|
||||
|
||||
def on_loaded():
|
||||
core.log("GPS plugin loaded for %s" % device)
|
||||
logging.info("GPS plugin loaded for %s" % device)
|
||||
|
||||
|
||||
def on_ready(agent):
|
||||
global running
|
||||
|
||||
if os.path.exists(device):
|
||||
core.log("enabling GPS bettercap's module for %s" % device)
|
||||
logging.info("enabling GPS bettercap's module for %s" % device)
|
||||
try:
|
||||
agent.run('gps off')
|
||||
except:
|
||||
@ -220,7 +220,7 @@ def on_ready(agent):
|
||||
agent.run('gps on')
|
||||
running = True
|
||||
else:
|
||||
core.log("no GPS detected")
|
||||
logging.info("no GPS detected")
|
||||
|
||||
|
||||
def on_handshake(agent, filename, access_point, client_station):
|
||||
@ -229,7 +229,7 @@ def on_handshake(agent, filename, access_point, client_station):
|
||||
gps = info['gps']
|
||||
gps_filename = filename.replace('.pcap', '.gps.json')
|
||||
|
||||
core.log("saving GPS to %s (%s)" % (gps_filename, gps))
|
||||
logging.info("saving GPS to %s (%s)" % (gps_filename, gps))
|
||||
with open(gps_filename, 'w+t') as fp:
|
||||
json.dump(gps, fp)
|
||||
```
|
||||
|
@ -6,6 +6,7 @@ import time
|
||||
import argparse
|
||||
from http.server import HTTPServer
|
||||
import shutil
|
||||
import logging
|
||||
import yaml
|
||||
|
||||
sys.path.insert(0,
|
||||
@ -13,7 +14,6 @@ sys.path.insert(0,
|
||||
'../sdcard/rootfs/root/pwnagotchi/scripts/'))
|
||||
|
||||
from pwnagotchi.ui.display import Display, VideoHandler
|
||||
import core
|
||||
|
||||
|
||||
class CustomDisplay(Display):
|
||||
@ -22,11 +22,11 @@ class CustomDisplay(Display):
|
||||
if self._video_address is not None:
|
||||
self._httpd = HTTPServer((self._video_address, self._video_port),
|
||||
CustomVideoHandler)
|
||||
core.log("ui available at http://%s:%d/" % (self._video_address,
|
||||
logging.info("ui available at http://%s:%d/" % (self._video_address,
|
||||
self._video_port))
|
||||
self._httpd.serve_forever()
|
||||
else:
|
||||
core.log("could not get ip of usb0, video server not starting")
|
||||
logging.info("could not get ip of usb0, video server not starting")
|
||||
|
||||
def _on_view_rendered(self, img):
|
||||
CustomVideoHandler.render(img)
|
||||
@ -45,7 +45,7 @@ class CustomVideoHandler(VideoHandler):
|
||||
try:
|
||||
img.save("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), format='PNG')
|
||||
except BaseException:
|
||||
core.log("could not write preview")
|
||||
logging.exception("could not write preview")
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == '/':
|
||||
@ -69,7 +69,7 @@ class CustomVideoHandler(VideoHandler):
|
||||
with open("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), 'rb') as fp:
|
||||
shutil.copyfileobj(fp, self.wfile)
|
||||
except BaseException:
|
||||
core.log("could not open preview")
|
||||
logging.exception("could not open preview")
|
||||
else:
|
||||
self.send_response(404)
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import logging
|
||||
import requests
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
import core
|
||||
|
||||
|
||||
class Client(object):
|
||||
def __init__(self, hostname='localhost', scheme='http', port=8081, username='user', password='pass'):
|
||||
@ -19,11 +18,11 @@ class Client(object):
|
||||
return r.json()
|
||||
except Exception as e:
|
||||
if r.status_code == 200:
|
||||
core.log("error while decoding json: error='%s' resp='%s'" % (e, r.text))
|
||||
logging.error("error while decoding json: error='%s' resp='%s'" % (e, r.text))
|
||||
else:
|
||||
err = "error %d: %s" % (r.status_code, r.text.strip())
|
||||
if verbose_errors:
|
||||
core.log(err)
|
||||
logging.info(err)
|
||||
raise Exception(err)
|
||||
return r.text
|
||||
|
||||
|
@ -1,24 +1,7 @@
|
||||
import sys
|
||||
import glob
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
from threading import Lock
|
||||
from datetime import datetime
|
||||
|
||||
logfile = None
|
||||
loglock = Lock()
|
||||
|
||||
|
||||
def log(msg):
|
||||
tstamp = str(datetime.now())
|
||||
line = "[%s] %s" % (tstamp, msg.rstrip())
|
||||
print(line)
|
||||
sys.stdout.flush()
|
||||
if logfile is not None:
|
||||
with loglock:
|
||||
with open(logfile, 'a+t') as fp:
|
||||
fp.write("%s\n" % line)
|
||||
|
||||
|
||||
def secs_to_hhmmss(secs):
|
||||
|
@ -2,11 +2,10 @@
|
||||
import os
|
||||
import argparse
|
||||
import time
|
||||
import traceback
|
||||
import logging
|
||||
|
||||
import yaml
|
||||
|
||||
import core
|
||||
import pwnagotchi
|
||||
import pwnagotchi.utils as utils
|
||||
import pwnagotchi.version as version
|
||||
@ -28,8 +27,12 @@ parser.add_argument('--manual', dest="do_manual", action="store_true", default=F
|
||||
parser.add_argument('--clear', dest="do_clear", action="store_true", default=False,
|
||||
help="Clear the ePaper display and exit.")
|
||||
|
||||
parser.add_argument('--debug', dest="debug", action="store_true", default=False,
|
||||
help="Enable debug logs.")
|
||||
|
||||
args = parser.parse_args()
|
||||
config = utils.load_config(args)
|
||||
utils.setup_logging(args, config)
|
||||
|
||||
if args.do_clear:
|
||||
print("clearing the display ...")
|
||||
@ -75,19 +78,18 @@ plugins.on('loaded')
|
||||
display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
|
||||
agent = Agent(view=display, config=config)
|
||||
|
||||
core.log("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, version.version))
|
||||
logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, version.version))
|
||||
# for key, value in config['personality'].items():
|
||||
# core.log(" %s: %s" % (key, value))
|
||||
# logging.info(" %s: %s" % (key, value))
|
||||
|
||||
for _, plugin in plugins.loaded.items():
|
||||
core.log("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
|
||||
logging.info("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
|
||||
|
||||
if args.do_manual:
|
||||
core.log("entering manual mode ...")
|
||||
logging.info("entering manual mode ...")
|
||||
|
||||
log = SessionParser(config['main']['log'])
|
||||
|
||||
core.log("the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
|
||||
logging.info("the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
|
||||
log.duration_human,
|
||||
log.epochs,
|
||||
log.train_epochs,
|
||||
@ -98,17 +100,18 @@ if args.do_manual:
|
||||
while True:
|
||||
display.on_manual_mode(log)
|
||||
time.sleep(1)
|
||||
|
||||
if config['twitter']['enabled'] and log.is_new() and Agent.is_connected() and log.handshakes > 0:
|
||||
import tweepy
|
||||
|
||||
core.log("detected a new session and internet connectivity!")
|
||||
logging.info("detected a new session and internet connectivity!")
|
||||
|
||||
picture = '/dev/shm/pwnagotchi.png'
|
||||
|
||||
display.update()
|
||||
display.update(force=True)
|
||||
display.image().save(picture, 'png')
|
||||
display.set('status', 'Tweeting...')
|
||||
display.update()
|
||||
display.update(force=True)
|
||||
|
||||
try:
|
||||
auth = tweepy.OAuthHandler(config['twitter']['consumer_key'], config['twitter']['consumer_secret'])
|
||||
@ -119,14 +122,12 @@ if args.do_manual:
|
||||
api.update_with_media(filename=picture, status=tweet)
|
||||
log.save_session_id()
|
||||
|
||||
core.log("tweeted: %s" % tweet)
|
||||
logging.info("tweeted: %s" % tweet)
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error while tweeting")
|
||||
|
||||
quit()
|
||||
|
||||
core.logfile = config['main']['log']
|
||||
|
||||
agent.start_ai()
|
||||
agent.setup_events()
|
||||
agent.set_starting()
|
||||
@ -151,7 +152,7 @@ while True:
|
||||
agent.set_channel(ch)
|
||||
|
||||
if not agent.is_stale() and agent.any_activity():
|
||||
core.log("%d access points on channel %d" % (len(aps), ch))
|
||||
logging.info("%d access points on channel %d" % (len(aps), ch))
|
||||
|
||||
# for each ap on this channel
|
||||
for ap in aps:
|
||||
@ -170,5 +171,4 @@ while True:
|
||||
# affect ours ... neat ^_^
|
||||
agent.next_epoch()
|
||||
except Exception as e:
|
||||
core.log("main loop exception: %s" % e)
|
||||
core.log("%s" % traceback.format_exc())
|
||||
logging.exception("main loop exception")
|
||||
|
@ -4,6 +4,7 @@ import os
|
||||
import re
|
||||
import socket
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import _thread
|
||||
|
||||
import core
|
||||
@ -82,7 +83,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
plugins.on('rebooting', self)
|
||||
|
||||
def setup_events(self):
|
||||
core.log("connecting to %s ..." % self.url)
|
||||
logging.info("connecting to %s ..." % self.url)
|
||||
|
||||
for tag in self._config['bettercap']['silence']:
|
||||
try:
|
||||
@ -109,30 +110,30 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
s = self.session()
|
||||
for iface in s['interfaces']:
|
||||
if iface['name'] == mon_iface:
|
||||
core.log("found monitor interface: %s" % iface['name'])
|
||||
logging.info("found monitor interface: %s" % iface['name'])
|
||||
has_mon = True
|
||||
break
|
||||
|
||||
if has_mon is False:
|
||||
if mon_start_cmd is not None and mon_start_cmd != '':
|
||||
core.log("starting monitor interface ...")
|
||||
logging.info("starting monitor interface ...")
|
||||
self.run('!%s' % mon_start_cmd)
|
||||
else:
|
||||
core.log("waiting for monitor interface %s ..." % mon_iface)
|
||||
logging.info("waiting for monitor interface %s ..." % mon_iface)
|
||||
time.sleep(1)
|
||||
|
||||
core.log("supported channels: %s" % self._supported_channels)
|
||||
core.log("handshakes will be collected inside %s" % self._config['bettercap']['handshakes'])
|
||||
logging.info("supported channels: %s" % self._supported_channels)
|
||||
logging.info("handshakes will be collected inside %s" % self._config['bettercap']['handshakes'])
|
||||
|
||||
self._reset_wifi_settings()
|
||||
|
||||
wifi_running = self.is_module_running('wifi')
|
||||
if wifi_running and restart:
|
||||
core.log("restarting wifi module ...")
|
||||
logging.debug("restarting wifi module ...")
|
||||
self.restart('wifi.recon')
|
||||
self.run('wifi.clear')
|
||||
elif not wifi_running:
|
||||
core.log("starting wifi module ...")
|
||||
logging.debug("starting wifi module ...")
|
||||
self.start('wifi.recon')
|
||||
|
||||
self.start_advertising()
|
||||
@ -150,13 +151,13 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
for ch in self._epoch.non_overlapping_channels:
|
||||
if ch not in busy_channels:
|
||||
self._epoch.non_overlapping_channels[ch] += 1
|
||||
core.log("channel %d is free from %d epochs" % (ch, self._epoch.non_overlapping_channels[ch]))
|
||||
logging.info("channel %d is free from %d epochs" % (ch, self._epoch.non_overlapping_channels[ch]))
|
||||
elif self._epoch.non_overlapping_channels[ch] > 0:
|
||||
self._epoch.non_overlapping_channels[ch] -= 1
|
||||
# report any channel that has been free for at least 3 epochs
|
||||
for ch, num_epochs_free in self._epoch.non_overlapping_channels.items():
|
||||
if num_epochs_free >= 3:
|
||||
core.log("channel %d has been free for %d epochs" % (ch, num_epochs_free))
|
||||
logging.info("channel %d has been free for %d epochs" % (ch, num_epochs_free))
|
||||
self.set_free_channel(ch)
|
||||
|
||||
def recon(self):
|
||||
@ -172,14 +173,14 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
if not channels:
|
||||
self._current_channel = 0
|
||||
# core.log("RECON %ds" % recon_time)
|
||||
logging.debug("RECON %ds" % recon_time)
|
||||
self.run('wifi.recon.channel clear')
|
||||
else:
|
||||
# core.log("RECON %ds ON CHANNELS %s" % (recon_time, ','.join(map(str, channels))))
|
||||
logging.debug("RECON %ds ON CHANNELS %s" % (recon_time, ','.join(map(str, channels))))
|
||||
try:
|
||||
self.run('wifi.recon.channel %s' % ','.join(map(str, channels)))
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
|
||||
self.wait_for(recon_time, sleeping=False)
|
||||
|
||||
@ -204,7 +205,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
if self._filter_included(ap):
|
||||
aps.append(ap)
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
|
||||
aps.sort(key=lambda ap: ap['channel'])
|
||||
return self.set_access_points(aps)
|
||||
@ -289,7 +290,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
self._view.set_closest_peer(peer)
|
||||
|
||||
def _save_recovery_data(self):
|
||||
core.log("writing recovery data to %s ..." % RECOVERY_DATA_FILE)
|
||||
logging.warning("writing recovery data to %s ..." % RECOVERY_DATA_FILE)
|
||||
with open(RECOVERY_DATA_FILE, 'w') as fp:
|
||||
data = {
|
||||
'started_at': self._started_at,
|
||||
@ -304,7 +305,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
try:
|
||||
with open(RECOVERY_DATA_FILE, 'rt') as fp:
|
||||
data = json.load(fp)
|
||||
core.log("found recovery data: %s" % data)
|
||||
logging.info("found recovery data: %s" % data)
|
||||
self._started_at = data['started_at']
|
||||
self._epoch.epoch = data['epoch']
|
||||
self._handshakes = data['handshakes']
|
||||
@ -312,7 +313,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
self._last_pwnd = data['last_pwnd']
|
||||
|
||||
if delete:
|
||||
core.log("deleting %s" % RECOVERY_DATA_FILE)
|
||||
logging.info("deleting %s" % RECOVERY_DATA_FILE)
|
||||
os.unlink(RECOVERY_DATA_FILE)
|
||||
except:
|
||||
if not no_exceptions:
|
||||
@ -323,7 +324,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
self.run('events.clear')
|
||||
|
||||
core.log("event polling started ...")
|
||||
logging.debug("event polling started ...")
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
@ -349,21 +350,21 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
new_shakes += 1
|
||||
ap_and_station = self._find_ap_sta_in(sta_mac, ap_mac, s)
|
||||
if ap_and_station is None:
|
||||
core.log("!!! captured new handshake: %s !!!" % key)
|
||||
logging.warning("!!! captured new handshake: %s !!!" % key)
|
||||
self._last_pwnd = ap_mac
|
||||
plugins.on('handshake', self, filename, ap_mac, sta_mac)
|
||||
else:
|
||||
(ap, sta) = ap_and_station
|
||||
self._last_pwnd = ap['hostname'] if ap['hostname'] != '' and ap[
|
||||
'hostname'] != '<hidden>' else ap_mac
|
||||
core.log("!!! captured new handshake on channel %d: %s (%s) -> %s [%s (%s)] !!!" % ( \
|
||||
logging.warning("!!! captured new handshake on channel %d: %s (%s) -> %s [%s (%s)] !!!" % ( \
|
||||
ap['channel'],
|
||||
sta['mac'], sta['vendor'],
|
||||
ap['hostname'], ap['mac'], ap['vendor']))
|
||||
plugins.on('handshake', self, filename, ap, sta)
|
||||
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
|
||||
finally:
|
||||
self._update_handshakes(new_shakes)
|
||||
@ -404,7 +405,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
return self._history[who] < self._config['personality']['max_interactions']
|
||||
|
||||
def _on_miss(self, who):
|
||||
core.log("it looks like %s is not in range anymore :/" % who)
|
||||
logging.info("it looks like %s is not in range anymore :/" % who)
|
||||
self._epoch.track(miss=True)
|
||||
self._view.on_miss(who)
|
||||
|
||||
@ -416,18 +417,18 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
if 'is an unknown BSSID' in error:
|
||||
self._on_miss(who)
|
||||
else:
|
||||
core.log("error: %s" % e)
|
||||
logging.error("%s" % e)
|
||||
|
||||
def associate(self, ap, throttle=0):
|
||||
if self.is_stale():
|
||||
core.log("recon is stale, skipping assoc(%s)" % ap['mac'])
|
||||
logging.debug("recon is stale, skipping assoc(%s)" % ap['mac'])
|
||||
return
|
||||
|
||||
if self._config['personality']['associate'] and self._should_interact(ap['mac']):
|
||||
self._view.on_assoc(ap)
|
||||
|
||||
try:
|
||||
core.log("sending association frame to %s (%s %s) on channel %d [%d clients]..." % ( \
|
||||
logging.info("sending association frame to %s (%s %s) on channel %d [%d clients]..." % ( \
|
||||
ap['hostname'], ap['mac'], ap['vendor'], ap['channel'], len(ap['clients'])))
|
||||
self.run('wifi.assoc %s' % ap['mac'])
|
||||
self._epoch.track(assoc=True)
|
||||
@ -441,14 +442,14 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
def deauth(self, ap, sta, throttle=0):
|
||||
if self.is_stale():
|
||||
core.log("recon is stale, skipping deauth(%s)" % sta['mac'])
|
||||
logging.debug("recon is stale, skipping deauth(%s)" % sta['mac'])
|
||||
return
|
||||
|
||||
if self._config['personality']['deauth'] and self._should_interact(sta['mac']):
|
||||
self._view.on_deauth(sta)
|
||||
|
||||
try:
|
||||
core.log("deauthing %s (%s) from %s (%s %s) on channel %d ..." % (
|
||||
logging.info("deauthing %s (%s) from %s (%s %s) on channel %d ..." % (
|
||||
sta['mac'], sta['vendor'], ap['hostname'], ap['mac'], ap['vendor'], ap['channel']))
|
||||
self.run('wifi.deauth %s' % sta['mac'])
|
||||
self._epoch.track(deauth=True)
|
||||
@ -462,7 +463,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
def set_channel(self, channel, verbose=True):
|
||||
if self.is_stale():
|
||||
core.log("recon is stale, skipping set_channel(%d)" % channel)
|
||||
logging.debug("recon is stale, skipping set_channel(%d)" % channel)
|
||||
return
|
||||
|
||||
# if in the previous loop no client stations has been deauthenticated
|
||||
@ -478,10 +479,12 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
if channel != self._current_channel:
|
||||
if self._current_channel != 0 and wait > 0:
|
||||
if verbose:
|
||||
core.log("waiting for %ds on channel %d ..." % (wait, self._current_channel))
|
||||
logging.info("waiting for %ds on channel %d ..." % (wait, self._current_channel))
|
||||
else:
|
||||
logging.debug("waiting for %ds on channel %d ..." % (wait, self._current_channel))
|
||||
self.wait_for(wait)
|
||||
if verbose and self._epoch.any_activity:
|
||||
core.log("CHANNEL %d" % channel)
|
||||
logging.info("CHANNEL %d" % channel)
|
||||
try:
|
||||
self.run('wifi.recon.channel %d' % channel)
|
||||
self._current_channel = channel
|
||||
@ -491,7 +494,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
plugins.on('channel_hop', self, channel)
|
||||
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.error("error: %s" % e)
|
||||
|
||||
def is_stale(self):
|
||||
return self._epoch.num_missed > self._config['personality']['max_misses_for_recon']
|
||||
@ -502,7 +505,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
def _reboot(self):
|
||||
self.set_rebooting()
|
||||
self._save_recovery_data()
|
||||
core.log("rebooting the system ...")
|
||||
logging.warning("rebooting the system ...")
|
||||
os.system("/usr/bin/sync")
|
||||
os.system("/usr/sbin/shutdown -r now")
|
||||
|
||||
@ -514,24 +517,24 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
# after X misses during an epoch, set the status to lonely
|
||||
if was_stale:
|
||||
core.log("agent missed %d interactions -> lonely" % did_miss)
|
||||
logging.warning("agent missed %d interactions -> lonely" % did_miss)
|
||||
self.set_lonely()
|
||||
# after X times being bored, the status is set to sad
|
||||
elif self._epoch.inactive_for >= self._config['personality']['sad_num_epochs']:
|
||||
core.log("%d epochs with no activity -> sad" % self._epoch.inactive_for)
|
||||
logging.warning("%d epochs with no activity -> sad" % self._epoch.inactive_for)
|
||||
self.set_sad()
|
||||
# after X times being inactive, the status is set to bored
|
||||
elif self._epoch.inactive_for >= self._config['personality']['bored_num_epochs']:
|
||||
core.log("%d epochs with no activity -> bored" % self._epoch.inactive_for)
|
||||
logging.warning("%d epochs with no activity -> bored" % self._epoch.inactive_for)
|
||||
self.set_bored()
|
||||
# after X times being active, the status is set to happy / excited
|
||||
elif self._epoch.active_for >= self._config['personality']['excited_num_epochs']:
|
||||
core.log("%d epochs with activity -> excited" % self._epoch.active_for)
|
||||
logging.warning("%d epochs with activity -> excited" % self._epoch.active_for)
|
||||
self.set_excited()
|
||||
|
||||
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
|
||||
|
||||
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
|
||||
core.log("%d epochs without visible access points -> rebooting ..." % self._epoch.blind_for)
|
||||
logging.critical("%d epochs without visible access points -> rebooting ..." % self._epoch.blind_for)
|
||||
self._reboot()
|
||||
self._epoch.blind_for = 0
|
||||
|
@ -7,16 +7,16 @@ import warnings
|
||||
# https://stackoverflow.com/questions/15777951/how-to-suppress-pandas-future-warning
|
||||
warnings.simplefilter(action='ignore', category=FutureWarning)
|
||||
|
||||
import core
|
||||
import logging
|
||||
|
||||
|
||||
def load(config, agent, epoch, from_disk=True):
|
||||
config = config['ai']
|
||||
if not config['enabled']:
|
||||
core.log("ai disabled")
|
||||
logging.info("ai disabled")
|
||||
return False
|
||||
|
||||
core.log("[ai] bootstrapping dependencies ...")
|
||||
logging.info("[ai] bootstrapping dependencies ...")
|
||||
|
||||
from stable_baselines import A2C
|
||||
from stable_baselines.common.policies import MlpLstmPolicy
|
||||
@ -27,16 +27,16 @@ def load(config, agent, epoch, from_disk=True):
|
||||
env = wrappers.Environment(agent, epoch)
|
||||
env = DummyVecEnv([lambda: env])
|
||||
|
||||
core.log("[ai] bootstrapping model ...")
|
||||
logging.info("[ai] bootstrapping model ...")
|
||||
|
||||
a2c = A2C(MlpLstmPolicy, env, **config['params'])
|
||||
|
||||
if from_disk and os.path.exists(config['path']):
|
||||
core.log("[ai] loading %s ..." % config['path'])
|
||||
logging.info("[ai] loading %s ..." % config['path'])
|
||||
a2c.load(config['path'], env)
|
||||
else:
|
||||
core.log("[ai] model created:")
|
||||
logging.info("[ai] model created:")
|
||||
for key, value in config['params'].items():
|
||||
core.log(" %s: %s" % (key, value))
|
||||
logging.info(" %s: %s" % (key, value))
|
||||
|
||||
return a2c
|
||||
|
@ -1,5 +1,6 @@
|
||||
import time
|
||||
import threading
|
||||
import logging
|
||||
|
||||
import core
|
||||
import pwnagotchi
|
||||
@ -87,13 +88,13 @@ class Epoch(object):
|
||||
aps_per_chan[ch_idx] += 1.0
|
||||
sta_per_chan[ch_idx] += len(ap['clients'])
|
||||
except IndexError as e:
|
||||
core.log("got data on channel %d, we can store %d channels" % (ap['channel'], wifi.NumChannels))
|
||||
logging.error("got data on channel %d, we can store %d channels" % (ap['channel'], wifi.NumChannels))
|
||||
|
||||
for peer in peers:
|
||||
try:
|
||||
peers_per_chan[peer.last_channel - 1] += 1.0
|
||||
except IndexError as e:
|
||||
core.log(
|
||||
logging.error(
|
||||
"got peer data on channel %d, we can store %d channels" % (peer.last_channel, wifi.NumChannels))
|
||||
|
||||
# normalize
|
||||
@ -172,7 +173,7 @@ class Epoch(object):
|
||||
self._epoch_data['reward'] = self._reward(self.epoch + 1, self._epoch_data)
|
||||
self._epoch_data_ready.set()
|
||||
|
||||
core.log("[epoch %d] duration=%s slept_for=%s blind=%d inactive=%d active=%d hops=%d missed=%d "
|
||||
logging.info("[epoch %d] duration=%s slept_for=%s blind=%d inactive=%d active=%d hops=%d missed=%d "
|
||||
"deauths=%d assocs=%d handshakes=%d cpu=%d%% mem=%d%% temperature=%dC reward=%s" % (
|
||||
self.epoch,
|
||||
core.secs_to_hhmmss(self.epoch_duration),
|
||||
|
@ -1,8 +1,8 @@
|
||||
import logging
|
||||
import gym
|
||||
from gym import spaces
|
||||
import numpy as np
|
||||
|
||||
import core
|
||||
import pwnagotchi.ai.featurizer as featurizer
|
||||
import pwnagotchi.ai.reward as reward
|
||||
from pwnagotchi.ai.parameter import Parameter
|
||||
@ -83,7 +83,7 @@ class Environment(gym.Env):
|
||||
return params
|
||||
|
||||
def _next_epoch(self):
|
||||
# core.log("[ai] waiting for epoch to finish ...")
|
||||
logging.debug("[ai] waiting for epoch to finish ...")
|
||||
return self._epoch.wait_for_epoch_data()
|
||||
|
||||
def _apply_policy(self, policy):
|
||||
@ -110,7 +110,7 @@ class Environment(gym.Env):
|
||||
return self.last['state_v'], self.last['reward'], not self._agent.is_training(), {}
|
||||
|
||||
def reset(self):
|
||||
# core.log("[ai] resetting environment ...")
|
||||
# logging.info("[ai] resetting environment ...")
|
||||
self._epoch_num = 0
|
||||
state = self._next_epoch()
|
||||
self.last['state'] = state
|
||||
@ -120,7 +120,7 @@ class Environment(gym.Env):
|
||||
def _render_histogram(self, hist):
|
||||
for ch in range(featurizer.histogram_size):
|
||||
if hist[ch]:
|
||||
core.log(" CH %d: %s" % (ch + 1, hist[ch]))
|
||||
logging.info(" CH %d: %s" % (ch + 1, hist[ch]))
|
||||
|
||||
def render(self, mode='human', close=False, force=False):
|
||||
# when using a vectorialized environment, render gets called twice
|
||||
@ -133,18 +133,13 @@ class Environment(gym.Env):
|
||||
|
||||
self._last_render = self._epoch_num
|
||||
|
||||
core.log("[ai] --- training epoch %d/%d ---" % (self._epoch_num, self._agent.training_epochs()))
|
||||
core.log("[ai] REWARD: %f" % self.last['reward'])
|
||||
logging.info("[ai] --- training epoch %d/%d ---" % (self._epoch_num, self._agent.training_epochs()))
|
||||
logging.info("[ai] REWARD: %f" % self.last['reward'])
|
||||
|
||||
# core.log("[ai] policy: %s" % ', '.join("%s:%s" % (name, value) for name, value in self.last['params'].items()))
|
||||
logging.debug("[ai] policy: %s" % ', '.join("%s:%s" % (name, value) for name, value in self.last['params'].items()))
|
||||
|
||||
core.log("[ai] observation:")
|
||||
logging.info("[ai] observation:")
|
||||
for name, value in self.last['state'].items():
|
||||
if 'histogram' in name:
|
||||
core.log(" %s" % name.replace('_histogram', ''))
|
||||
logging.info(" %s" % name.replace('_histogram', ''))
|
||||
self._render_histogram(value)
|
||||
|
||||
# core.log("[ai] outcome:")
|
||||
# for name, value in self.last['state'].items():
|
||||
# if 'histogram' not in name:
|
||||
# core.log(" %s: %s" % (name, value))
|
||||
|
@ -4,8 +4,7 @@ import time
|
||||
import random
|
||||
import os
|
||||
import json
|
||||
|
||||
import core
|
||||
import logging
|
||||
|
||||
import pwnagotchi.plugins as plugins
|
||||
import pwnagotchi.ai as ai
|
||||
@ -56,7 +55,7 @@ class Stats(object):
|
||||
def load(self):
|
||||
with self._lock:
|
||||
if os.path.exists(self.path) and os.path.getsize(self.path) > 0:
|
||||
core.log("[ai] loading %s" % self.path)
|
||||
logging.info("[ai] loading %s" % self.path)
|
||||
with open(self.path, 'rt') as fp:
|
||||
obj = json.load(fp)
|
||||
|
||||
@ -66,7 +65,7 @@ class Stats(object):
|
||||
|
||||
def save(self):
|
||||
with self._lock:
|
||||
core.log("[ai] saving %s" % self.path)
|
||||
logging.info("[ai] saving %s" % self.path)
|
||||
|
||||
data = json.dumps({
|
||||
'born_at': self.born_at,
|
||||
@ -114,7 +113,7 @@ class AsyncTrainer(object):
|
||||
_thread.start_new_thread(self._ai_worker, ())
|
||||
|
||||
def _save_ai(self):
|
||||
core.log("[ai] saving model to %s ..." % self._nn_path)
|
||||
logging.info("[ai] saving model to %s ..." % self._nn_path)
|
||||
temp = "%s.tmp" % self._nn_path
|
||||
self._model.save(temp)
|
||||
os.replace(temp, self._nn_path)
|
||||
@ -133,15 +132,15 @@ class AsyncTrainer(object):
|
||||
|
||||
def on_ai_policy(self, new_params):
|
||||
plugins.on('ai_policy', self, new_params)
|
||||
core.log("[ai] setting new policy:")
|
||||
logging.info("[ai] setting new policy:")
|
||||
for name, value in new_params.items():
|
||||
if name in self._config['personality']:
|
||||
curr_value = self._config['personality'][name]
|
||||
if curr_value != value:
|
||||
core.log("[ai] ! %s: %s -> %s" % (name, curr_value, value))
|
||||
logging.info("[ai] ! %s: %s -> %s" % (name, curr_value, value))
|
||||
self._config['personality'][name] = value
|
||||
else:
|
||||
core.log("[ai] param %s not in personality configuration!" % name)
|
||||
logging.error("[ai] param %s not in personality configuration!" % name)
|
||||
|
||||
self.run('set wifi.ap.ttl %d' % self._config['personality']['ap_ttl'])
|
||||
self.run('set wifi.sta.ttl %d' % self._config['personality']['sta_ttl'])
|
||||
@ -152,12 +151,12 @@ class AsyncTrainer(object):
|
||||
plugins.on('ai_ready', self)
|
||||
|
||||
def on_ai_best_reward(self, r):
|
||||
core.log("[ai] best reward so far: %s" % r)
|
||||
logging.info("[ai] best reward so far: %s" % r)
|
||||
self._view.on_motivated(r)
|
||||
plugins.on('ai_best_reward', self, r)
|
||||
|
||||
def on_ai_worst_reward(self, r):
|
||||
core.log("[ai] worst reward so far: %s" % r)
|
||||
logging.info("[ai] worst reward so far: %s" % r)
|
||||
self._view.on_demotivated(r)
|
||||
plugins.on('ai_worst_reward', self, r)
|
||||
|
||||
@ -174,12 +173,12 @@ class AsyncTrainer(object):
|
||||
self._model.env.render()
|
||||
# enter in training mode?
|
||||
if random.random() > self._config['ai']['laziness']:
|
||||
core.log("[ai] learning for %d epochs ..." % epochs_per_episode)
|
||||
logging.info("[ai] learning for %d epochs ..." % epochs_per_episode)
|
||||
try:
|
||||
self.set_training(True, epochs_per_episode)
|
||||
self._model.learn(total_timesteps=epochs_per_episode, callback=self.on_ai_training_step)
|
||||
except Exception as e:
|
||||
core.log("[ai] error while training: %s" % e)
|
||||
logging.exception("[ai] error while training")
|
||||
finally:
|
||||
self.set_training(False)
|
||||
obs = self._model.env.reset()
|
||||
|
@ -37,6 +37,8 @@ class SessionParser(object):
|
||||
self.last_saved_session_id = self.last_session_id
|
||||
|
||||
def _parse_datetime(self, dt):
|
||||
dt = dt.split('.')[0]
|
||||
dt = dt.split(',')[0]
|
||||
dt = datetime.strptime(dt.split('.')[0], '%Y-%m-%d %H:%M:%S')
|
||||
return time.mktime(dt.timetuple())
|
||||
|
||||
|
@ -2,9 +2,9 @@ import time
|
||||
import json
|
||||
import _thread
|
||||
import threading
|
||||
import logging
|
||||
from scapy.all import Dot11, Dot11FCS, Dot11Elt, RadioTap, sendp, sniff
|
||||
|
||||
import core
|
||||
import pwnagotchi.ui.faces as faces
|
||||
|
||||
import pwnagotchi.mesh.wifi as wifi
|
||||
@ -54,7 +54,6 @@ class Advertiser(object):
|
||||
self._lost_peer_cb = lost_cb
|
||||
|
||||
def on_face_change(self, old, new):
|
||||
# core.log("face change: %s -> %s" % (old, new))
|
||||
self.update({'face': new})
|
||||
|
||||
def start(self):
|
||||
@ -84,12 +83,12 @@ class Advertiser(object):
|
||||
self._stopped.set()
|
||||
|
||||
def _sender(self):
|
||||
core.log("started advertiser thread (period:%s sid:%s) ..." % (str(self._period), self._me.session_id))
|
||||
logging.info("started advertiser thread (period:%s sid:%s) ..." % (str(self._period), self._me.session_id))
|
||||
while self._running:
|
||||
try:
|
||||
sendp(self._frame, iface=self._iface, verbose=False, count=5, inter=self._period)
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
time.sleep(self._period)
|
||||
|
||||
def _on_advertisement(self, src_session_id, channel, rssi, adv):
|
||||
@ -97,7 +96,7 @@ class Advertiser(object):
|
||||
with self._peers_lock:
|
||||
if ident not in self._peers:
|
||||
peer = Peer(src_session_id, channel, rssi, adv)
|
||||
core.log("detected unit %s (v%s) on channel %d (%s dBm) [sid:%s pwnd_tot:%d uptime:%d]" % ( \
|
||||
logging.info("detected unit %s (v%s) on channel %d (%s dBm) [sid:%s pwnd_tot:%d uptime:%d]" % ( \
|
||||
peer.full_name(),
|
||||
peer.version(),
|
||||
channel,
|
||||
@ -158,10 +157,10 @@ class Advertiser(object):
|
||||
raise Exception("unknown frame id %d" % dot11elt.ID)
|
||||
|
||||
except Exception as e:
|
||||
core.log("error decoding packet from %s: %s" % (dot11.addr3, e))
|
||||
logging.exception("error decoding packet from %s" % dot11.addr3)
|
||||
|
||||
def _listener(self):
|
||||
# core.log("started advertisements listener ...")
|
||||
# logging.info("started advertisements listener ...")
|
||||
expr = "type mgt subtype beacon and ether src %s" % wifi.SignatureAddress
|
||||
sniff(iface=self._iface, filter=expr, prn=self._on_packet, store=0, stop_filter=lambda x: self._stopped.isSet())
|
||||
|
||||
@ -173,7 +172,7 @@ class Advertiser(object):
|
||||
for ident, peer in self._peers.items():
|
||||
inactive_for = peer.inactive_for()
|
||||
if inactive_for >= Advertiser.MAX_STALE_TIME:
|
||||
core.log("peer %s lost (inactive for %ds)" % (peer.full_name(), inactive_for))
|
||||
logging.info("peer %s lost (inactive for %ds)" % (peer.full_name(), inactive_for))
|
||||
self._lost_peer_cb(peer)
|
||||
stale.append(ident)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import time
|
||||
import logging
|
||||
|
||||
import pwnagotchi.mesh.wifi as wifi
|
||||
import pwnagotchi.ui.faces as faces
|
||||
import core
|
||||
|
||||
|
||||
class Peer(object):
|
||||
@ -18,10 +18,10 @@ class Peer(object):
|
||||
|
||||
def update(self, sid, channel, rssi, adv):
|
||||
if self.name() != adv['name']:
|
||||
core.log("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), adv['name']))
|
||||
logging.info("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), adv['name']))
|
||||
|
||||
if self.session_id != sid:
|
||||
core.log("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, sid))
|
||||
logging.info("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, sid))
|
||||
|
||||
self.presence[channel - 1] += 1
|
||||
self.adv = adv
|
||||
|
@ -1,6 +1,6 @@
|
||||
import _thread
|
||||
import logging
|
||||
|
||||
import core
|
||||
import pwnagotchi
|
||||
import pwnagotchi.version as version
|
||||
import pwnagotchi.plugins as plugins
|
||||
@ -35,7 +35,7 @@ class AsyncAdvertiser(object):
|
||||
self._advertiser.start()
|
||||
self._view.on_state_change('face', self._advertiser.on_face_change)
|
||||
else:
|
||||
core.log("advertising is disabled")
|
||||
logging.warning("advertising is disabled")
|
||||
|
||||
def _on_new_unit(self, peer):
|
||||
self._view.on_new_peer(peer)
|
||||
|
@ -5,15 +5,16 @@ __license__ = 'GPL3'
|
||||
__description__ = 'An example plugin for pwnagotchi that implements all the available callbacks.'
|
||||
__enabled__ = False # IMPORTANT: set this to True to enable your plugin.
|
||||
|
||||
import logging
|
||||
|
||||
from pwnagotchi.ui.components import LabeledValue
|
||||
from pwnagotchi.ui.view import BLACK
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
import core
|
||||
|
||||
|
||||
# called when the plugin is loaded
|
||||
def on_loaded():
|
||||
core.log("WARNING: plugin %s should be disabled!" % __name__)
|
||||
logging.warning("WARNING: plugin %s should be disabled!" % __name__)
|
||||
|
||||
|
||||
# called to setup the ui elements
|
||||
@ -39,7 +40,7 @@ def on_display_setup(display):
|
||||
|
||||
# called when everything is ready and the main loop is about to start
|
||||
def on_ready(agent):
|
||||
core.log("unit is ready")
|
||||
logging.info("unit is ready")
|
||||
# you can run custom bettercap commands if you want
|
||||
# agent.run('ble.recon on')
|
||||
# or set a custom state
|
||||
|
@ -5,7 +5,7 @@ __license__ = 'GPL3'
|
||||
__description__ = 'Save GPS coordinates whenever an handshake is captured.'
|
||||
__enabled__ = True # set to false if you just don't use GPS
|
||||
|
||||
import core
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
|
||||
@ -15,14 +15,14 @@ running = False
|
||||
|
||||
|
||||
def on_loaded():
|
||||
core.log("GPS plugin loaded for %s" % device)
|
||||
logging.info("GPS plugin loaded for %s" % device)
|
||||
|
||||
|
||||
def on_ready(agent):
|
||||
global running
|
||||
|
||||
if os.path.exists(device):
|
||||
core.log("enabling GPS bettercap's module for %s" % device)
|
||||
logging.info("enabling GPS bettercap's module for %s" % device)
|
||||
try:
|
||||
agent.run('gps off')
|
||||
except:
|
||||
@ -33,7 +33,7 @@ def on_ready(agent):
|
||||
agent.run('gps on')
|
||||
running = True
|
||||
else:
|
||||
core.log("no GPS detected")
|
||||
logging.warning("no GPS detected")
|
||||
|
||||
|
||||
def on_handshake(agent, filename, access_point, client_station):
|
||||
@ -42,6 +42,6 @@ def on_handshake(agent, filename, access_point, client_station):
|
||||
gps = info['gps']
|
||||
gps_filename = filename.replace('.pcap', '.gps.json')
|
||||
|
||||
core.log("saving GPS to %s (%s)" % (gps_filename, gps))
|
||||
logging.info("saving GPS to %s (%s)" % (gps_filename, gps))
|
||||
with open(gps_filename, 'w+t') as fp:
|
||||
json.dump(gps, fp)
|
||||
|
@ -2,7 +2,7 @@ import _thread
|
||||
from threading import Lock
|
||||
|
||||
import shutil
|
||||
import core
|
||||
import logging
|
||||
import os
|
||||
import pwnagotchi, pwnagotchi.plugins as plugins
|
||||
|
||||
@ -78,13 +78,12 @@ class Display(View):
|
||||
self._render_cb = None
|
||||
self._display = None
|
||||
self._httpd = None
|
||||
self.canvas = None
|
||||
|
||||
if self._enabled:
|
||||
self._init_display()
|
||||
else:
|
||||
self.on_render(self._on_view_rendered)
|
||||
core.log("display module is disabled")
|
||||
logging.warning("display module is disabled")
|
||||
|
||||
if self._video_enabled:
|
||||
_thread.start_new_thread(self._http_serve, ())
|
||||
@ -92,10 +91,10 @@ class Display(View):
|
||||
def _http_serve(self):
|
||||
if self._video_address is not None:
|
||||
self._httpd = HTTPServer((self._video_address, self._video_port), VideoHandler)
|
||||
core.log("ui available at http://%s:%d/" % (self._video_address, self._video_port))
|
||||
logging.info("ui available at http://%s:%d/" % (self._video_address, self._video_port))
|
||||
self._httpd.serve_forever()
|
||||
else:
|
||||
core.log("could not get ip of usb0, video server not starting")
|
||||
logging.info("could not get ip of usb0, video server not starting")
|
||||
|
||||
def _is_inky(self):
|
||||
return self._display_type in ('inkyphat', 'inky')
|
||||
@ -111,14 +110,14 @@ class Display(View):
|
||||
|
||||
def _init_display(self):
|
||||
if self._is_inky():
|
||||
core.log("initializing inky display")
|
||||
logging.info("initializing inky display")
|
||||
from inky import InkyPHAT
|
||||
self._display = InkyPHAT(self._display_color)
|
||||
self._display.set_border(InkyPHAT.BLACK)
|
||||
self._render_cb = self._inky_render
|
||||
|
||||
elif self._is_papirus():
|
||||
core.log("initializing papirus display")
|
||||
logging.info("initializing papirus display")
|
||||
from pwnagotchi.ui.papirus.epd import EPD
|
||||
os.environ['EPD_SIZE'] = '2.0'
|
||||
self._display = EPD()
|
||||
@ -126,7 +125,7 @@ class Display(View):
|
||||
self._render_cb = self._papirus_render
|
||||
|
||||
elif self._is_waveshare1():
|
||||
core.log("initializing waveshare v1 display")
|
||||
logging.info("initializing waveshare v1 display")
|
||||
from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
|
||||
self._display = EPD()
|
||||
self._display.init(self._display.lut_full_update)
|
||||
@ -135,7 +134,7 @@ class Display(View):
|
||||
self._render_cb = self._waveshare_render
|
||||
|
||||
elif self._is_waveshare2():
|
||||
core.log("initializing waveshare v2 display")
|
||||
logging.info("initializing waveshare v2 display")
|
||||
from pwnagotchi.ui.waveshare.v2.waveshare import EPD
|
||||
self._display = EPD()
|
||||
self._display.init(self._display.FULL_UPDATE)
|
||||
@ -144,63 +143,61 @@ class Display(View):
|
||||
self._render_cb = self._waveshare_render
|
||||
|
||||
else:
|
||||
core.log("unknown display type %s" % self._display_type)
|
||||
logging.critical("unknown display type %s" % self._display_type)
|
||||
|
||||
plugins.on('display_setup', self._display)
|
||||
|
||||
self.on_render(self._on_view_rendered)
|
||||
|
||||
def image(self):
|
||||
img = None
|
||||
if self.canvas is not None:
|
||||
img = self.canvas if self._rotation == 0 else self.canvas.rotate(-self._rotation)
|
||||
return img
|
||||
|
||||
def _inky_render(self):
|
||||
if self._display_color != 'mono':
|
||||
display_colors = 3
|
||||
else:
|
||||
display_colors = 2
|
||||
|
||||
imgbuf = self.canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
|
||||
|
||||
img_buffer = self._canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
|
||||
if self._display_color == 'red':
|
||||
imgbuf.putpalette([
|
||||
img_buffer.putpalette([
|
||||
255, 255, 255, # index 0 is white
|
||||
0, 0, 0, # index 1 is black
|
||||
255, 0, 0 # index 2 is red
|
||||
])
|
||||
elif self._display_color == 'yellow':
|
||||
imgbuf.putpalette([
|
||||
img_buffer.putpalette([
|
||||
255, 255, 255, # index 0 is white
|
||||
0, 0, 0, # index 1 is black
|
||||
255, 255, 0 # index 2 is yellow
|
||||
])
|
||||
else:
|
||||
imgbuf.putpalette([
|
||||
img_buffer.putpalette([
|
||||
255, 255, 255, # index 0 is white
|
||||
0, 0, 0 # index 1 is black
|
||||
])
|
||||
|
||||
self._display.set_image(imgbuf)
|
||||
self._display.set_image(img_buffer)
|
||||
self._display.show()
|
||||
|
||||
def _papirus_render(self):
|
||||
self._display.display(self.canvas)
|
||||
self._display.display(self._canvas)
|
||||
self._display.partial_update()
|
||||
|
||||
def _waveshare_render(self):
|
||||
buf = self._display.getbuffer(self.canvas)
|
||||
buf = self._display.getbuffer(self._canvas)
|
||||
if self._is_waveshare1():
|
||||
self._display.display(buf)
|
||||
elif self._is_waveshare2():
|
||||
self._display.displayPartial(buf)
|
||||
|
||||
def image(self):
|
||||
img = None
|
||||
if self._canvas is not None:
|
||||
img = self._canvas if self._rotation == 0 else self._canvas.rotate(-self._rotation)
|
||||
return img
|
||||
|
||||
def _on_view_rendered(self, img):
|
||||
# core.log("display::_on_view_rendered")
|
||||
VideoHandler.render(img)
|
||||
|
||||
if self._enabled:
|
||||
self.canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
|
||||
self._canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
|
||||
if self._render_cb is not None:
|
||||
self._render_cb()
|
||||
|
@ -1,6 +1,7 @@
|
||||
import _thread
|
||||
from threading import Lock
|
||||
import time
|
||||
import logging
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
import core
|
||||
@ -114,7 +115,7 @@ class View(object):
|
||||
_thread.start_new_thread(self._refresh_handler, ())
|
||||
self._ignore_changes = ()
|
||||
else:
|
||||
core.log("ui.fps is 0, the display will only update for major changes")
|
||||
logging.warning("ui.fps is 0, the display will only update for major changes")
|
||||
self._ignore_changes = ('uptime', 'name')
|
||||
|
||||
def add_element(self, key, elem):
|
||||
@ -135,7 +136,7 @@ class View(object):
|
||||
|
||||
def _refresh_handler(self):
|
||||
delay = 1.0 / self._config['ui']['fps']
|
||||
# core.log("view refresh handler started with period of %.2fs" % delay)
|
||||
# logging.info("view refresh handler started with period of %.2fs" % delay)
|
||||
|
||||
while True:
|
||||
name = self._state.get('name')
|
||||
@ -313,10 +314,10 @@ class View(object):
|
||||
self.set('status', self._voice.custom(text))
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
def update(self, force=False):
|
||||
with self._lock:
|
||||
changes = self._state.changes(ignore=self._ignore_changes)
|
||||
if len(changes):
|
||||
if force or len(changes):
|
||||
self._canvas = Image.new('1', (self._width, self._height), WHITE)
|
||||
drawer = ImageDraw.Draw(self._canvas)
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import yaml
|
||||
import os
|
||||
import logging
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/823196/yaml-merge-in-python
|
||||
def merge_config(user, default):
|
||||
@ -22,3 +24,19 @@ def load_config(args):
|
||||
config = merge_config(user_config, config)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def setup_logging(args, config):
|
||||
formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s")
|
||||
root = logging.getLogger()
|
||||
|
||||
root.setLevel(logging.DEBUG if args.debug else logging.INFO)
|
||||
|
||||
if config['main']['log']:
|
||||
file_handler = logging.FileHandler(config['main']['log'])
|
||||
file_handler.setFormatter(formatter)
|
||||
root.addHandler(file_handler)
|
||||
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setFormatter(formatter)
|
||||
root.addHandler(console_handler)
|
||||
|
Loading…
x
Reference in New Issue
Block a user