diff --git a/deploy/install_netwatch.sh b/deploy/install_netwatch.sh index 90aca49..eff1bc4 100755 --- a/deploy/install_netwatch.sh +++ b/deploy/install_netwatch.sh @@ -13,6 +13,7 @@ set -euo pipefail REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" WLAN=wlan1 # T3U dongle — change to wlan0 if reverting to onboard +WLAN_FB=wlan0 # onboard fallback sudo systemctl stop yaris-uplink-wait.service 2>/dev/null || true sudo systemctl stop yaris-netwatch.timer yaris-netwatch.service 2>/dev/null || true @@ -39,9 +40,27 @@ if nmcli connection show phone-hotspot >/dev/null 2>&1; then 802-11-wireless.mtu 1400 fi -# Disable onboard wlan0 so it doesn't interfere -sudo nmcli device disconnect wlan0 2>/dev/null || true -sudo nmcli device set wlan0 managed no 2>/dev/null || true +# Create wlan0 fallback profiles (lower autoconnect-priority so wlan1 wins) +# home-wifi-fb: same SSID as home-wifi but on wlan0 +HOME_SSID=$(nmcli -g 802-11-wireless.ssid connection show home-wifi 2>/dev/null || true) +HOME_PSK=$(sudo nmcli -g 802-11-wireless-security.psk connection show --show-secrets home-wifi 2>/dev/null || true) +if [ -n "$HOME_SSID" ] && [ -n "$HOME_PSK" ]; then + nmcli connection delete home-wifi-fb 2>/dev/null || true + sudo nmcli connection add \ + type wifi \ + con-name home-wifi-fb \ + ifname "$WLAN_FB" \ + ssid "$HOME_SSID" \ + -- \ + wifi-security.key-mgmt wpa-psk \ + wifi-security.psk "$HOME_PSK" \ + connection.autoconnect yes \ + connection.autoconnect-priority 5 + echo "Created home-wifi-fb fallback on $WLAN_FB" +fi + +# Re-enable wlan0 as a managed (but low-priority) fallback +sudo nmcli device set "$WLAN_FB" managed yes 2>/dev/null || true sudo cp "$REPO_DIR/deploy/yaris-netwatch.service" /etc/systemd/system/yaris-netwatch.service sudo cp "$REPO_DIR/deploy/yaris-netwatch.timer" /etc/systemd/system/yaris-netwatch.timer diff --git a/deploy/yaris_uplink.py b/deploy/yaris_uplink.py index a5bfb8a..fc2058d 100644 --- a/deploy/yaris_uplink.py +++ b/deploy/yaris_uplink.py @@ -12,7 +12,8 @@ import uuid PHONE_CONNECTION = "phone-hotspot" HOME_CONNECTION = "home-wifi" AP_CONNECTION = "Hotspot" -INTERFACE = "wlan1" # TP-Link T3U dongle — all client + AP traffic +PRIMARY_INTERFACE = "wlan1" # TP-Link T3U dongle — preferred +FALLBACK_INTERFACE = "wlan0" # onboard — used if T3U is absent STATUS_PATH = "/var/lib/yaris-obd/uplink-status.json" PHONE_KEYFILE = ( "/etc/NetworkManager/system-connections/" @@ -24,6 +25,24 @@ class UplinkError(RuntimeError): pass +def _interface_exists(iface): + """Return True if the kernel sees this network interface.""" + return os.path.exists(f"/sys/class/net/{iface}") + + +def resolve_interface(): + """Return PRIMARY_INTERFACE if it exists, else FALLBACK_INTERFACE.""" + if _interface_exists(PRIMARY_INTERFACE): + return PRIMARY_INTERFACE + if _interface_exists(FALLBACK_INTERFACE): + return FALLBACK_INTERFACE + return PRIMARY_INTERFACE # return primary anyway; nmcli will error clearly + + +# Module-level convenience — resolved once at startup. +INTERFACE = resolve_interface() + + def run_nmcli(*args, timeout=45, check=True): process = subprocess.run( ["nmcli", *args], @@ -149,6 +168,7 @@ def write_status(action, error=None): status = { "action": action, "active_connection": current, + "interface": INTERFACE, "error": error, "last_phone_ip": last_phone_ip, "updated_at": time.time(), @@ -182,6 +202,17 @@ def restore_fallback(): if activate(HOME_CONNECTION): write_status("connected_home") return True + # If the primary interface (wlan1) failed, try the wlan0 fallback profiles + if INTERFACE == PRIMARY_INTERFACE and _interface_exists(FALLBACK_INTERFACE): + # Temporarily try connections bound to wlan0 + for conn in (f"{HOME_CONNECTION}-fb", AP_CONNECTION): + proc = subprocess.run( + ["nmcli", "--wait", "30", "connection", "up", conn], + capture_output=True, text=True, timeout=35, + ) + if proc.returncode == 0: + write_status(f"fallback_wlan0_{conn}") + return True if activate(AP_CONNECTION): write_status("restored_local_hotspot") return True