From e8589bb34dd55ea89314524d3d8581509f2e064d Mon Sep 17 00:00:00 2001 From: Aayush Sharma Date: Thu, 2 Oct 2025 15:38:00 +0530 Subject: [PATCH] feat: add cross-platform notification system and update setup docs --- requirements.txt | 4 +- setup.md | 303 ++++++++++++++++++++++++------ wifi_auto_login.py | 445 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 657 insertions(+), 95 deletions(-) diff --git a/requirements.txt b/requirements.txt index 64851aa..6c0779b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ python>=3.6 requests>=2.25.1 -sqlite3 +plyer>=2.0 +win10toast>=0.9 +keyring>=23.0.0 # optional; remove if you don't implement keyring diff --git a/setup.md b/setup.md index 63947d1..21e204e 100644 --- a/setup.md +++ b/setup.md @@ -1,5 +1,14 @@ -# Kindly go through the steps to locally setup the script on your device. +# WiFi Auto-Auth Setup Guide with Notification System ___ + +## ๐Ÿ”” New Features: Desktop Notifications +The script now includes a cross-platform notification system that alerts you about: +- โœ… Successful login attempts +- โŒ Failed login attempts +- ๐Ÿ”Œ Network connectivity issues +- ๐Ÿ”„ Already logged in status +- โฑ๏ธ Connection timeouts + ## 1. Install Dependencies Run the following command to install the requirements: @@ -7,92 +16,284 @@ Run the following command to install the requirements: ```bash pip install -r requirements.txt ``` -## 2. Find Your Network's Login URL and Payload -``` -2.1 Connect to your WiFi network manually. -2.2 Open the login page in a browser (http://192.168.x.x:8090/httpclient.html). -2.3 Inspect the login form (Right-click โ†’ Inspect โ†’ Network Tab). -2.4 Find the POST request URL inside the Network tab(should look like http://192.168.x.x:8090/login.xml). -2.5 Copy the form data parameters (like username, password, a, etc.). + +### Platform-specific notification setup: + +#### **Linux:** +- Install `libnotify` if not present: + ```bash + sudo apt-get install libnotify-bin # Debian/Ubuntu + sudo dnf install libnotify # Fedora + sudo pacman -S libnotify # Arch + ``` + +#### **Windows:** +- Notifications work out of the box with Windows 10/11 +- For better support, install: `pip install win10toast` + +#### **macOS:** +- Notifications use native macOS notification center +- No additional setup required + +## 2. Configure Your Network Settings + +The script now uses a JSON configuration file located at: +- **Linux/Mac:** `~/.wifi_auto_auth_config.json` +- **Windows:** `C:\Users\YourUsername\.wifi_auto_auth_config.json` + +### 2.1 First Run +On first run, the script will create a default configuration file. Edit this file with your network details. + +### 2.2 Find Your Network's Login URL and Payload ``` -## 3. Edit ```wifi_auto_login.py``` file -Modify the ```def wifi_login()``` function to match your payload parameters. -i.e: +1. Connect to your WiFi network manually +2. Open the login page in a browser (typically http://192.168.x.x:8090/httpclient.html) +3. Open Developer Tools (F12) โ†’ Network Tab +4. Log in manually and find the POST request (usually to /login.xml) +5. Copy the request URL and form data parameters ``` + +### 2.3 Edit the Configuration File + +Example configuration: +```json { "login_url": "http://192.168.100.1:8090/login.xml", - "username": "your_username", - "password": "your_password", + "username": "your_actual_username", + "password": "your_actual_password", "payload_params": { "mode": "191", - "username": "your_username", - "password": "your_password", + "username": "your_actual_username", + "password": "your_actual_password", "a": "dynamic", "producttype": "0" }, - "db_name": "wifi_log.db" + "notifications": { + "enabled": true, + "sound": true, + "on_success": true, + "on_failure": true, + "on_network_error": true, + "on_already_logged_in": true + }, + "db_name": "wifi_log.db", + "retry_attempts": 3, + "retry_delay": 5 } ``` -Note: a โ†’ Keep "dynamic" if the value changes on every login attempt. -## 4. Run the Script -Run the Python script to log in automatically: -``` +### Configuration Options: + +| Option | Description | Values | +|--------|-------------|--------| +| `login_url` | Your WiFi portal login URL | String | +| `username` | Your WiFi username | String | +| `password` | Your WiFi password | String | +| `payload_params.a` | Session parameter | "dynamic" or static value | +| `notifications.enabled` | Enable/disable all notifications | true/false | +| `notifications.sound` | Play sound with notifications | true/false | +| `notifications.on_success` | Notify on successful login | true/false | +| `notifications.on_failure` | Notify on failed login | true/false | +| `notifications.on_network_error` | Notify on network issues | true/false | +| `notifications.on_already_logged_in` | Notify if already connected | true/false | +| `retry_attempts` | Number of retry attempts | Integer (1-10) | +| `retry_delay` | Delay between retries (seconds) | Integer | + +## 3. Test the Script + +Run the script manually to test: +```bash python wifi_auto_login.py ``` -## 5. Automate WiFi Login on System Boot: +You should see: +1. Console output showing the login attempt +2. A desktop notification with the result +3. Recent login history -#### **๐Ÿ”น Windows (Task Scheduler)** -5.1. Open **Task Scheduler** โ†’ **Create Basic Task**. -5.2. Set **Trigger** โ†’ **At Startup**. -5.3. Set **Action** โ†’ **Start a Program** โ†’ Browse for `python.exe`. -5.4. In **Arguments**, enter: - ```text - "C:\path\to\wifi_auto_login.py" - ``` -5.5. Save and enable the task. +## 4. Test Notifications ---- -#### **๐Ÿ”น Linux (Crontab)** -5.1. Open terminal and run: +To test if notifications are working on your system: +```bash +python -c "from plyer import notification; notification.notify(title='Test', message='Notifications working!')" +``` + +## 5. Automate WiFi Login on System Boot + +### ๐Ÿ”น Windows (Task Scheduler) +1. Open **Task Scheduler** โ†’ **Create Basic Task** +2. Name: "WiFi Auto Login" +3. Trigger: **At Startup** +4. Action: **Start a Program** +5. Program: `python.exe` or `pythonw.exe` (for no console window) +6. Arguments: `"C:\path\to\wifi_auto_login.py"` +7. Start in: `"C:\path\to\"` (directory containing the script) +8. Check "Run with highest privileges" + +### ๐Ÿ”น Linux (Systemd Service - Recommended) +1. Create a service file: ```bash - crontab -e + sudo nano /etc/systemd/system/wifi-auto-login.service + ``` + +2. Add content: + ```ini + [Unit] + Description=WiFi Auto Login Service + After=network-online.target + Wants=network-online.target + + [Service] + Type=oneshot + User=your_username + ExecStartPre=/bin/sleep 10 + ExecStart=/usr/bin/python3 /path/to/wifi_auto_login.py + RemainAfterExit=yes + + [Install] + WantedBy=multi-user.target ``` -5.2. Add this line at the end: + +3. Enable the service: ```bash - @reboot python3 /path/to/wifi_auto_login.py + sudo systemctl daemon-reload + sudo systemctl enable wifi-auto-login.service + sudo systemctl start wifi-auto-login.service ``` -5.3. Save and exit. ---- -#### **๐Ÿ”น macOS (Launch Agents)** -5.1. Create a `.plist` file in `~/Library/LaunchAgents/`: +### ๐Ÿ”น Linux (Crontab - Alternative) +```bash +crontab -e +# Add this line: +@reboot sleep 30 && /usr/bin/python3 /path/to/wifi_auto_login.py +``` + +### ๐Ÿ”น macOS (Launch Agent) +1. Create plist file: ```bash - nano ~/Library/LaunchAgents/wifi_auto_login.plist + nano ~/Library/LaunchAgents/com.wifi.autologin.plist ``` -5.2. Add this content: + +2. Add content: ```xml - + - + Label - wifi_auto_login + com.wifi.autologin ProgramArguments - /usr/bin/python3 - /path/to/wifi_auto_login.py + /usr/bin/python3 + /path/to/wifi_auto_login.py RunAtLoad - + StartInterval + 300 + StandardOutPath + /tmp/wifi-auto-login.log + StandardErrorPath + /tmp/wifi-auto-login-error.log + ``` -5.3. Save and enable it: + +3. Load the agent: ```bash - launchctl load ~/Library/LaunchAgents/wifi_auto_login.plist + launchctl load ~/Library/LaunchAgents/com.wifi.autologin.plist ``` -We have succesfully setup the script now the wifi or LAN will get connected **automatically on system startup**! +## 6. View Logs and Statistics + +The script maintains a SQLite database with all login attempts. To view logs: + +```python +# View last 10 login attempts +python -c "from wifi_auto_login import view_logs; view_logs(10)" +``` + +## 7. Troubleshooting + +### Notifications not working? + +1. **Linux:** Ensure `notify-send` is installed +2. **Windows:** Try running as administrator +3. **macOS:** Check System Preferences โ†’ Notifications โ†’ Python +4. **All platforms:** Test with the test command in step 4 + +### Script not running at startup? + +1. Check system logs: + - **Linux:** `journalctl -u wifi-auto-login.service` + - **Windows:** Event Viewer โ†’ Windows Logs โ†’ System + - **macOS:** `Console.app` โ†’ system.log + +2. Add a delay before execution (network might not be ready) + +### Can't find login URL? + +1. Try common patterns: + - `http://192.168.1.1:8090/login.xml` + - `http://192.168.0.1:8090/httpclient.html` + - `http://10.0.0.1/login` + +2. Check browser's network tab while logging in manually + +## 8. Security Notes + +- Configuration file contains credentials - keep it secure! +- Set appropriate file permissions: + ```bash + chmod 600 ~/.wifi_auto_auth_config.json # Linux/Mac + ``` +- Passwords are masked in logs +- Consider using environment variables for sensitive data +- The SQLite database is stored locally and logs are auto-cleaned after 30 days + +## 9. Customization + +### Custom Notification Icons +Place an icon file (`.png` or `.ico`) in the script directory and update the code: +```python +notification.notify( + title=title, + message=message, + app_icon="path/to/icon.png", # Add your icon path + timeout=10 +) +``` + +### Notification Sounds +Customize notification sounds by modifying the platform-specific functions in the `NotificationHandler` class. + +## 10. Uninstall + +To remove the auto-login service: + +**Windows:** +- Delete the Task Scheduler task + +**Linux (systemd):** +```bash +sudo systemctl stop wifi-auto-login.service +sudo systemctl disable wifi-auto-login.service +sudo rm /etc/systemd/system/wifi-auto-login.service +``` + +**macOS:** +```bash +launchctl unload ~/Library/LaunchAgents/com.wifi.autologin.plist +rm ~/Library/LaunchAgents/com.wifi.autologin.plist +``` + +## Need Help? + +- Check the logs: Script creates detailed logs in `wifi_log.db` +- Enable debug mode by adding verbose output in the script +- Open an issue on GitHub with your log output (remove sensitive data!) + +--- +Successfully set up! Your WiFi will now connect automatically with desktop notifications! ๐ŸŽ‰ \ No newline at end of file diff --git a/wifi_auto_login.py b/wifi_auto_login.py index c2a4153..25179d3 100644 --- a/wifi_auto_login.py +++ b/wifi_auto_login.py @@ -2,10 +2,164 @@ import requests import datetime import re +import json +import os +import time +import platform +import subprocess +import sys +import argparse +from pathlib import Path +from urllib.parse import urlparse -# Database setup +# Try to import plyer for notifications, fallback to native solutions if not available +try: + from plyer import notification + PLYER_AVAILABLE = True +except Exception: + PLYER_AVAILABLE = False + +# Optional Windows toast library (used only in windows fallback) +try: + import win10toast + WIN10TOAST_AVAILABLE = True +except Exception: + WIN10TOAST_AVAILABLE = False + +# Configuration file path +CONFIG_FILE = Path.home() / ".wifi_auto_auth_config.json" DB_NAME = "wifi_log.db" +class NotificationHandler: + """Cross-platform notification handler""" + + def __init__(self, enabled=True, sound=True): + self.enabled = enabled + self.sound = sound + self.system = platform.system() # always available now + + def send(self, title, message, urgency="normal"): + """Send a desktop notification""" + if not self.enabled: + return + + try: + if PLYER_AVAILABLE: + notification.notify( + title=title, + message=message, + app_icon=None, + timeout=10, + ) + return + # Fallback if plyer not available + if self.system == "Linux": + self._linux_notify(title, message, urgency) + elif self.system == "Darwin": + self._macos_notify(title, message) + elif self.system == "Windows": + self._windows_notify(title, message) + else: + print(f"๐Ÿ”” {title}: {message}") + except Exception as e: + print(f"Notification failed: {e}") + print(f"๐Ÿ”” {title}: {message}") + + def _linux_notify(self, title, message, urgency): + """Linux notification using notify-send""" + cmd = ["notify-send", title, message, f"--urgency={urgency}"] + # note: notify-send doesn't have a cross-distro 'sound' flag; you can play a sound separately if needed + try: + subprocess.run(cmd, check=False) + except FileNotFoundError: + print(f"notify-send not found; fallback to console -> {title}: {message}") + + def _macos_notify(self, title, message): + """macOS notification using osascript""" + # Escape double-quotes in message/title + safe_title = title.replace('"', '\\"') + safe_message = message.replace('"', '\\"') + script = f'display notification "{safe_message}" with title "{safe_title}"' + subprocess.run(["osascript", "-e", script], check=False) + + def _windows_notify(self, title, message): + """Windows notification using win10toast or powershell fallback""" + # Prefer win10toast if installed + try: + if WIN10TOAST_AVAILABLE: + from win10toast import ToastNotifier + toaster = ToastNotifier() + toaster.show_toast(title, message, duration=10, threaded=True) + else: + # Use PowerShell balloon as fallback - escape single quotes + safe_title = title.replace("'", "''") + safe_message = message.replace("'", "''") + ps_script = f""" + $app = New-Object -ComObject WScript.Shell + $app.Popup('{safe_message}', 10, '{safe_title}', 64) + """ + subprocess.run(["powershell", "-NoProfile", "-Command", ps_script], check=False) + except Exception: + print(f"Windows notification fallback -> {title}: {message}") + +def _deep_update(dst, src): + """Deep merge src dict into dst dict""" + for k, v in src.items(): + if isinstance(v, dict) and isinstance(dst.get(k), dict): + _deep_update(dst[k], v) + else: + dst[k] = v + +class Config: + """Configuration manager for the WiFi auto-login script""" + + @staticmethod + def load(): + """Load configuration from file""" + default_config = { + "login_url": "http://192.168.100.1:8090/login.xml", + "username": "your_username", + "password": "your_password", + "payload_params": { + "mode": "191", + "username": "your_username", + "password": "your_password", + "a": "dynamic", + "producttype": "0" + }, + "notifications": { + "enabled": True, + "sound": True, + "on_success": True, + "on_failure": True, + "on_network_error": True, + "on_already_logged_in": True + }, + "db_name": DB_NAME, + "retry_attempts": 3, + "retry_delay": 5 + } + + if CONFIG_FILE.exists(): + try: + with open(CONFIG_FILE, 'r') as f: + user_config = json.load(f) + _deep_update(default_config, user_config) + except json.JSONDecodeError: + print("โš ๏ธ Invalid config file, using defaults") + else: + Config.save(default_config) + print(f"๐Ÿ“ Created default config at: {CONFIG_FILE}") + print("Please edit this file with your WiFi credentials!") + + return default_config + + @staticmethod + def save(config): + """Save configuration to file""" + with open(CONFIG_FILE, 'w') as f: + json.dump(config, f, indent=4) + def setup_database(): """Create the database and table if they do not exist.""" conn = sqlite3.connect(DB_NAME) @@ -18,94 +172,299 @@ def setup_database(): password TEXT, a TEXT, response_status TEXT, - response_message TEXT + response_message TEXT, + notification_sent INTEGER DEFAULT 0 ) """) conn.commit() conn.close() -def log_attempt(username, password, a, response_status, response_message): +def log_attempt(username, password, a, response_status, response_message, notification_sent=False): """Log each login attempt in the database.""" + ts = datetime.datetime.now().isoformat(sep=' ', timespec='seconds') conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() cursor.execute(""" - INSERT INTO login_attempts (timestamp, username, password, a, response_status, response_message) - VALUES (?, ?, ?, ?, ?, ?) - """, (datetime.datetime.now(), username, "******", a, response_status, response_message)) + INSERT INTO login_attempts (timestamp, username, password, a, response_status, response_message, notification_sent) + VALUES (?, ?, ?, ?, ?, ?, ?) + """, (ts, username, "******", a, str(response_status), response_message, int(bool(notification_sent)))) conn.commit() conn.close() def extract_message(response_text): - """Extracts the meaningful message from the XML response.""" - match = re.search(r"", response_text) - return match.group(1) if match else "Unknown response" + """Extracts the meaningful message from the XML response (best-effort).""" + # Try common CDATA + match = re.search(r"\s*\s*", response_text, re.DOTALL | re.IGNORECASE) + if match: + return match.group(1).strip() + # Try plain tag + match2 = re.search(r"(.*?)", response_text, re.DOTALL | re.IGNORECASE) + if match2: + return match2.group(1).strip() + # Try tag variant + match3 = re.search(r"(.*?)", response_text, re.DOTALL | re.IGNORECASE) + if match3: + return match3.group(1).strip() + # fallback to first 300 chars of plain text + return re.sub(r"\s+", " ", response_text).strip()[:300] or "No response" -def wifi_login(): - """Perform the WiFi login request and log the result.""" - url = "POST url from the inspect element" # Change Required - username = "username" - password = "password" - a_value = str(int(datetime.datetime.now().timestamp())) # Generate dynamic 'a' value, you may refer to the screenshots in the setup.md file - - payload = { - "mode": "191", - "username": username, - "password": password, - "a": a_value, - "producttype": "0" - } +def check_connectivity(url): + """Check if the network/login portal is reachable""" + try: + parsed = urlparse(url if '://' in url else 'http://' + url) + base_url = f"{parsed.scheme}://{parsed.netloc}" + response = requests.get(base_url, timeout=5) + return True + except requests.exceptions.RequestException: + return False + except Exception: + return False +def wifi_login(config, notifier): + """Perform the WiFi login request and log the result.""" + url = config["login_url"] + username = config["username"] + password = config["password"] + + # Check network connectivity first + if not check_connectivity(url): + error_msg = "Network unreachable or login portal not available" + print(f"โŒ› {error_msg}") + + if config["notifications"]["on_network_error"]: + notifier.send( + "WiFi Auto-Auth: Network Error", + error_msg, + urgency="critical" + ) + + log_attempt(username, password, "N/A", "NETWORK_ERROR", error_msg, True) + return False + + # Generate dynamic 'a' value if needed + if config["payload_params"].get("a") == "dynamic": + a_value = str(int(datetime.datetime.now().timestamp())) + else: + a_value = config["payload_params"].get("a", "") + + # Build payload - copy to avoid mutation + payload = dict(config["payload_params"]) + payload["username"] = username + payload["password"] = password + if "a" in payload: + payload["a"] = a_value + + notification_sent = False + try: - response = requests.post(url, data=payload) + response = requests.post(url, data=payload, timeout=10) response_status = response.status_code response_message = extract_message(response.text) - + print(f"\n๐Ÿ“Œ Login Attempt") - print(f"Time: {datetime.datetime.now()}") + print(f"Time: {datetime.datetime.now().isoformat(sep=' ', timespec='seconds')}") print(f"Username: {username}") - print(f"Session ID (a): {a_value}") + if a_value: + print(f"Session ID (a): {a_value}") print(f"Status: {response_status}") print(f"Message: {response_message}") print("-" * 80) - + + # Determine success/failure and send appropriate notification + success_keywords = ["success", "logged in", "authenticated", "welcome"] + already_logged_keywords = ["already", "exist", "active"] + + message_lower = response_message.lower() + + if any(keyword in message_lower for keyword in success_keywords): + if config["notifications"]["on_success"]: + notifier.send( + "WiFi Auto-Auth: Success โœ…", + f"Successfully logged in as {username}", + urgency="normal" + ) + notification_sent = True + elif any(keyword in message_lower for keyword in already_logged_keywords): + if config["notifications"]["on_already_logged_in"]: + notifier.send( + "WiFi Auto-Auth: Already Connected ๐Ÿ”„", + "You are already logged into the network", + urgency="low" + ) + notification_sent = True + else: + if config["notifications"]["on_failure"]: + notifier.send( + "WiFi Auto-Auth: Login Failed โŒ", + f"Failed: {response_message[:100]}", + urgency="critical" + ) + notification_sent = True + # Log the attempt in SQLite - log_attempt(username, password, a_value, response_status, response_message) - + log_attempt(username, password, a_value, str(response_status), response_message, notification_sent) + return response_status == 200 + + except requests.exceptions.Timeout: + error_msg = "Connection timeout - server took too long to respond" + print(f"โŒ› Timeout Error: {error_msg}") + if config["notifications"]["on_network_error"]: + notifier.send( + "WiFi Auto-Auth: Timeout โฑ๏ธ", + error_msg, + urgency="critical" + ) + notification_sent = True + log_attempt(username, password, a_value, "TIMEOUT", error_msg, notification_sent) + return False + except requests.exceptions.RequestException as e: - print(f"โŒ Error: {e}") - log_attempt(username, password, a_value, "FAILED", str(e)) + error_msg = str(e) + print(f"โŒ Error: {error_msg}") + if config["notifications"]["on_failure"]: + notifier.send( + "WiFi Auto-Auth: Error โŒ", + f"Connection error: {error_msg[:100]}", + urgency="critical" + ) + notification_sent = True + log_attempt(username, password, a_value, "FAILED", error_msg, notification_sent) + return False def view_logs(limit=5): """Display login logs in a readable format.""" conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() cursor.execute(""" - SELECT timestamp, username, a, response_status, response_message + SELECT timestamp, username, a, response_status, response_message, notification_sent FROM login_attempts ORDER BY timestamp DESC LIMIT ? """, (limit,)) - + logs = cursor.fetchall() conn.close() - + if not logs: print("No login attempts found.") return - - print("\n๐Ÿ“Œ Recent Login Attempts") + + print("\n๐Ÿ“‹ Recent Login Attempts") print("=" * 80) - + for log in logs: - timestamp, username, a, status, message = log + timestamp, username, a, status, message, notif = log print(f"Time: {timestamp}") print(f"Username: {username}") - print(f"Session ID (a): {a}") + if a and a != "N/A": + print(f"Session ID (a): {a}") print(f"Status: {status}") print(f"Message: {message}") + print(f"Notification Sent: {'Yes' if notif else 'No'}") print("-" * 80) +def clear_old_logs(days=30): + """Clear logs older than specified days""" + conn = sqlite3.connect(DB_NAME) + cursor = conn.cursor() + cutoff = datetime.datetime.now() - datetime.timedelta(days=days) + cutoff_iso = cutoff.isoformat(sep=' ', timespec='seconds') + cursor.execute("DELETE FROM login_attempts WHERE timestamp < ?", (cutoff_iso,)) + deleted = cursor.rowcount + conn.commit() + conn.close() + if deleted and deleted > 0: + print(f"๐Ÿ—‘๏ธ Cleared {deleted} old log entries") + +def parse_args(): + """Parse command line arguments""" + parser = argparse.ArgumentParser(description='WiFi Auto-Login Script with Notifications') + parser.add_argument('--no-notify', action='store_true', + help='Disable notifications for this run') + parser.add_argument('--test-notify', action='store_true', + help='Test notification system and exit') + parser.add_argument('--view-logs', type=int, metavar='N', + help='View last N login attempts and exit') + parser.add_argument('--clear-logs', type=int, metavar='DAYS', + help='Clear logs older than DAYS and exit') + return parser.parse_args() + +def main(): + """Main execution function""" + args = parse_args() + + # Load configuration + config = Config.load() + + # Handle test notification + if args.test_notify: + print("๐Ÿงช Testing notification system...") + test_notifier = NotificationHandler(enabled=True, sound=True) + test_notifier.send( + "WiFi Auto-Auth Test", + "โœ… Notifications are working correctly!", + urgency="normal" + ) + print("โœ… Test notification sent. Check your desktop notifications!") + return + + # Handle view logs + if args.view_logs is not None: + setup_database() + view_logs(args.view_logs) + return + + # Handle clear logs + if args.clear_logs is not None: + setup_database() + clear_old_logs(args.clear_logs) + return + + # Check if this is first run (default credentials) + if config["username"] == "your_username": + print("\nโš ๏ธ Please configure your WiFi credentials!") + print(f"Edit the config file at: {CONFIG_FILE}") + print("Then run this script again.") + return + + # Override notification settings if --no-notify is used + if args.no_notify: + config["notifications"]["enabled"] = False + print("๐Ÿ”• Notifications disabled for this run") + + # Initialize notification handler + notifier = NotificationHandler( + enabled=config["notifications"]["enabled"], + sound=config["notifications"].get("sound", True) + ) + + # Setup database + setup_database() + + # Clear old logs (older than 30 days) + clear_old_logs(30) + + # Attempt login with retry logic + max_retries = config.get("retry_attempts", 3) + retry_delay = config.get("retry_delay", 5) + + for attempt in range(max_retries): + if attempt > 0: + print(f"\n๐Ÿ”„ Retry attempt {attempt}/{max_retries - 1}") + time.sleep(retry_delay) + + success = wifi_login(config, notifier) + if success: + break + + # Show recent logs + view_logs(5) + if __name__ == "__main__": - setup_database() # Ensure the database is set up - wifi_login() # Attempt login - view_logs(5) # Show last 5 login attempts + # Install plyer if not available + if not PLYER_AVAILABLE: + print("๐Ÿ“ฆ plyer not installed. For better notification support, run:") + print(" pip install plyer") + print(" Using fallback notification methods...\n") + + main() \ No newline at end of file