Plugin code uses print() in several places instead of the logging
module. On a headless Pi Zero, print() output goes nowhere useful
while logging integrates with pwnagotchi's log system.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
'"success" in result' checks if the key exists in the dict (always
True for valid responses), not whether the operation succeeded.
result["success"] can KeyError if the key is missing.
Change all checks to result.get("success") which correctly returns
the boolean value or None if the key is absent.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_epoch calls agent.view() directly without checking hasattr first,
unlike every other method in the plugin. This crashes if the agent
has no view attribute (e.g., during early startup or in headless mode).
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_ui_setup computes a pos variable from options or defaults but
never uses it. The ui._lock context and logging.debug("Got here")
are leftover scaffolding with no effect.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_ready opens a subprocess.Popen to read journalctl but never uses
the result. The Popen object is never closed, leaking a file descriptor
and zombie process on every startup.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
Typo "wifi.interfaceface" should be "wifi.interface" in the debug
log for the bettercap set wifi.interface command result.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
Four robustness improvements to PiSugarServer I2C communication:
1. Race condition: build i2creg into temp list, swap atomically with
threading lock so UI thread never reads partial register data.
2. Bus recovery: add error counter with exponential backoff (3s-30s),
log suppression after 3 errors, and SMBus reconnect after 5
consecutive failures to recover from MCU deep sleep.
3. Write protection: restructure as try/finally so register 0x0B is
always re-enabled even if the middle write fails.
4. Shutdown safety: wrap I2C writes in try/except/finally so failures
are logged but never prevent pwnagotchi.shutdown() from executing.
Fixes#511
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
For PiSugar2/2Plus with max_charge_voltage_protection enabled,
battery_voltage was appended to voltage_history twice per cycle:
once inside the charge protection block and once unconditionally
at the end. This skews the trimmed-mean battery level calculation.
Make the final append conditional so each model appends exactly
once per cycle regardless of charge protection setting.
Fixes#509
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_loaded crashes with AttributeError when PiSugar is not connected
because it accesses self.ps without a None check. Also uses direct
dict access on self.options which crashes if keys are missing.
on_ui_update crashes when checking battery_plugged outside the
self.ready guard, hitting self.ps.get_battery_power_plugged on None.
Changes:
- Wrap self.ps access in on_loaded with None guard
- Use self.options.get() with safe defaults
- Move battery_plugged inside self.ready + self.ps check
- Downgrade "PiSugar is not ready" from info to debug
Fixes#507
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
The web UI checks for 'Pisugar 3' (with space, lowercase 's') but
the model detection sets self.model = 'PiSugar3' (no space, uppercase 'S').
This causes 5 PiSugar3-specific fields to never display their actual values.
Replace all occurrences to match the value set during initialization.
Fixes#505
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
PiSugar 3 users need graceful shutdown with e-ink feedback, boot-loop
prevention when charging from dead battery, and automatic recovery
when pisugar-server loses I2C connection after MCU wake.
- safe-shutdown.sh: stops pwnagotchi, draws sleeping face on e-ink,
powers off. Boot-loop guard skips shutdown when battery <10% and
charging.
- pisugar-watchdog.sh + systemd timer: detects MCU wake from deep
sleep and restarts pisugar-server when I2C is present but daemon
reports disconnected.
- epd-shutdown.py / epd-startup.py: e-ink display faces for
Waveshare V4. Exit silently on non-V4 displays.
Signed-off-by: CoderFX <4704376+CoderFX@users.noreply.github.com>
on_bcap_sys_log fires on every bettercap syslog event matching "wifi
error while hopping to channel". When bettercap is in a bad state, it
sends many such events per second. Each one triggers agent.run() to
flip wifi.recon, which also fails because bettercap is unstable. This
creates a cascade of TypeError errors filling the log — 61 errors in
a few minutes in observed logs.
Two fixes:
1. Safe Message access: use event.get() with isinstance check instead
of direct dict access into re.search(). Prevents TypeError when
Message is None or non-string, and KeyError if event structure is
unexpected.
2. Add 30-second cooldown: check self.LASTTRY before attempting a
recon flip, matching the debounce pattern already used in on_epoch
and _tryTurningItOffAndOnAgain. Update LASTTRY on all outcomes
(success, failure, exception) to prevent cascading retries.
Signed-off-by: CoderFX <4704376+CoderFX@users.noreply.github.com>
The whitelist in config.toml is checked in get_access_points() to
filter APs from active attacks, but bettercap still passively captures
handshakes from all networks including whitelisted ones. The
_on_event() handler processes wifi.client.handshake events without
any whitelist check, so handshakes from the user's own networks are
saved and reported as new captures.
Add whitelist filtering to _on_event() with two checks:
- By MAC address immediately after extracting ap_mac (catches
MAC-based whitelist entries before any processing)
- By hostname after _find_ap_sta_in() resolves the AP (catches
name-based whitelist entries)
When a whitelisted handshake is detected, the pcap file that
bettercap already wrote to disk is removed to prevent accumulation.
Signed-off-by: CoderFX <4704376+CoderFX@users.noreply.github.com>
- Fix interaction display to handle new history dict format
({count, first_seen} from handshake capture optimization PR)
- Escape preset names in HTML output to prevent XSS
- Deduplicate channel list to avoid scanning same channel twice
- Replace deprecated logging.warn() with logging.warning()
- Reduce default extra_channels from 15 to 5 (15 scans nearly all
2.4GHz channels every epoch, defeating focused scanning)
Signed-off-by: CoderFX <153912+CoderFX@users.noreply.github.com>
Signed-off-by: CoderFX <4704376+CoderFX@users.noreply.github.com>
agent.py:
- Fix _has_handshake() substring match bug: was matching partial MACs
(e.g. "AA:BB:CC" matching "AA:BB:CC:DD:EE:FF"), causing APs to be
skipped. Now splits key on ' -> ' and checks exact MAC match.
- Add time-based decay to interaction history: previously once an AP/STA
hit max_interactions it was permanently skipped for the session. Now
resets count after 5 minutes, allowing retry of stubborn targets.
- Cap recon time increase when inactive: was doubling (30s->60s), now
adds at most 15s to avoid long idle periods with fewer channel hops.
- Interleave populated and sparse channels instead of always hitting
most-populated first, giving sparse channels fair coverage.
- Use set for whitelist lookup (O(1) instead of O(n) per AP).
- Remove fragile mac[:13] prefix whitelist match, use full MAC only.
- Add backward compat for recovery data format change.
cli.py:
- Reduce inter-deauth sleep from 1.0s to 0.3s. The 1s delay was overly
conservative for nexmon firmware; 0.3s is sufficient and processes
multi-client APs 3x faster.
Signed-off-by: CoderFX <153912+CoderFX@users.noreply.github.com>
Signed-off-by: CoderFX <4704376+CoderFX@users.noreply.github.com>