# Monitoring Router Data Usage with Python (Linux & Windows)

Most routers have a hidden goldmine of usage stats—if you know where to look. I got tired of manually checking how much data we were using on our 300GB monthly plan, especially with big downloads and shared WiFi. So I wrote a Python script that:

* Logs into the router
    
* Grabs monthly and daily data usage
    
* Warns when I hit a usage threshold
    
* Shows total time online
    
* Works on both Windows and Linux
    
* Only runs **once a day** to avoid lag
    

No more surprises from the ISP.

### How It Works

My router is a Huawei model with a web interface at [`http://192.168.8.1`](http://192.168.8.1). It exposes data usage stats at this endpoint:

```bash
http://192.168.8.1/api/monitoring/month_statistics
```

The router responds with XML, so the script uses basic string slicing to extract values like:

* `<CurrentMonthDownload>`
    
* `<CurrentMonthUpload>`
    
* `<MonthDuration>`
    
* `<CurrentDayUsed>`, etc.
    

---

### Windows Version: GUI Notification

On Windows, I use the `plyer` package to pop up a notification if usage crosses 90% of the monthly cap.

```bash
pip install plyer
```

Here’s the script:

```bash
import requests
from datetime import timedelta
from plyer import notification

# Router URL
base_url = "http://192.168.8.1"
login_url = f"{base_url}/html/index.html"

# Login credentials
password = "Password123"  # Change this to your actual router's login password

# Step 1: Log in to the router
login_payload = {
    'Password': password
}
headers = {
    'Content-Type': 'application/x-www-form-urlencoded'
}

# Session to persist cookies and headers
session = requests.Session()

# You may need to modify this login step depending on your router's login form
login_response = session.post(login_url, data=login_payload, headers=headers)

if login_response.status_code == 200:
    print("Login successful")
else:
    print("Login failed!")
    exit()

# Router URL for data usage statistics
stats_url = "http://192.168.8.1/api/monitoring/month_statistics"

# Data limit in bytes (300GB = 300 * 1024^3)
data_limit = 300 * 1024 * 1024 * 1024
threshold = 0.9  # 90% usage threshold

# Step 1: Fetch data usage statistics from the router
response = session.get(stats_url)

if response.status_code == 200:
    # Parse XML response
    data = response.text
    download_start = data.find("<CurrentMonthDownload>") + len("<CurrentMonthDownload>")
    download_end = data.find("</CurrentMonthDownload>")
    upload_start = data.find("<CurrentMonthUpload>") + len("<CurrentMonthUpload>")
    upload_end = data.find("</CurrentMonthUpload>")
    duration_start = data.find("<MonthDuration>") + len("<MonthDuration>")
    duration_end = data.find("</MonthDuration>")
    clear_time_start = data.find("<MonthLastClearTime>") + len("<MonthLastClearTime>")
    clear_time_end = data.find("</MonthLastClearTime>")
    day_used_start = data.find("<CurrentDayUsed>") + len("<CurrentDayUsed>")
    day_used_end = data.find("</CurrentDayUsed>")
    day_duration_start = data.find("<CurrentDayDuration>") + len("<CurrentDayDuration>")
    day_duration_end = data.find("</CurrentDayDuration>")

    # Extract values
    current_download = int(data[download_start:download_end])
    current_upload = int(data[upload_start:upload_end])
    month_duration = int(data[duration_start:duration_end])
    last_clear_time = data[clear_time_start:clear_time_end]
    current_day_used = int(data[day_used_start:day_used_end])
    current_day_duration = int(data[day_duration_start:day_duration_end])

    # Calculate total data usage
    total_usage = current_download + current_upload
    usage_percentage = total_usage / data_limit * 100

    print(f"Total usage: {total_usage / (1024 ** 3):.2f} GB ({usage_percentage:.2f}% of 300 GB limit)")

    if usage_percentage >= threshold * 100:
        warning_message = f"Warning: You have used {usage_percentage:.2f}% of your 300 GB data limit."
        print(warning_message)

        # Show Windows pop-up notification
        notification.notify(
            title="Data Usage Warning",
            message=warning_message,
            app_name="Data Usage Monitor",
            timeout=10  # Notification lasts for 10 seconds
        )
    else:
        print("Data usage is below the warning threshold.")

    # Month and day statistics
    print(f"Data usage for the current day: {current_day_used / (1024 ** 3):.2f} GB")
   
    # Convert MonthDuration and CurrentDayDuration from seconds to a more readable format (hours, minutes)
    month_duration_readable = str(timedelta(seconds=month_duration))
    current_day_duration_readable = str(timedelta(seconds=current_day_duration))

    print(f"Total online time this month: {month_duration_readable}")
    print(f"Total online time today: {current_day_duration_readable}")
    print(f"Last data reset date: {last_clear_time}")
else:
    print(f"Failed to retrieve data usage statistics. Status code: {response.status_code}")
```

It also prints:

* Total GB used
    
* Current day usage
    
* Last reset date
    
* Time online this month and today
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756371481370/bed62f71-b401-4a78-a397-76be2039dbd0.png align="left")

### Linux Version: Terminal-Only

Since `notify-send` doesn’t work reliably with WSL or headless systems, the Linux version sticks to **terminal output only**:

```bash
print(f"Total WiFi usage: {usage:.2f} GB ({usage_percentage:.2f}%)")

if usage_percentage >= 80:
    print("*** Warning: You have used 80% of your 300 GB limit ***")
else:
    print("WiFi usage is below the warning threshold ✓")
```

I use [`subprocess.run`](http://subprocess.run)`()` if I *want* to hook in `notify-send`, but keep it disabled by default.

```bash

root@RHAYDEN:/home/rhayden/scripts# cat wifi_data_usage_checker.py
import requests
from datetime import timedelta
import subprocess

# Router URL
base_url = "http://192.168.8.1"
login_url = f"{base_url}/html/index.html"

# Login credentials
password = "Password123"

# Step 1: Log in to the router
login_payload = {
    'Password': password
}
headers = {
    'Content-Type': 'application/x-www-form-urlencoded'
}

# Session to persist cookies and headers
session = requests.Session()

# You may need to modify this login step depending on your router's login form
login_response = session.post(login_url, data=login_payload, headers=headers)

if login_response.status_code == 200:
    print("Login successful")
else:
    print("Login failed!")
    exit()

# Router URL for data usage statistics
stats_url = "http://192.168.8.1/api/monitoring/month_statistics"

# Data limit in bytes (300GB = 300 * 1024^3)
data_limit = 300 * 1024 * 1024 * 1024
threshold = 0.8  # 80% usage threshold

# Step 1: Fetch data usage statistics from the router
response = session.get(stats_url)

if response.status_code == 200:
    # Parse XML response
    data = response.text
    download_start = data.find("<CurrentMonthDownload>") + len("<CurrentMonthDownload>")
    download_end = data.find("</CurrentMonthDownload>")
    upload_start = data.find("<CurrentMonthUpload>") + len("<CurrentMonthUpload>")
    upload_end = data.find("</CurrentMonthUpload>")
    duration_start = data.find("<MonthDuration>") + len("<MonthDuration>")
    duration_end = data.find("</MonthDuration>")
    clear_time_start = data.find("<MonthLastClearTime>") + len("<MonthLastClearTime>")
    clear_time_end = data.find("</MonthLastClearTime>")
    day_used_start = data.find("<CurrentDayUsed>") + len("<CurrentDayUsed>")
    day_used_end = data.find("</CurrentDayUsed>")
    day_duration_start = data.find("<CurrentDayDuration>") + len("<CurrentDayDuration>")
    day_duration_end = data.find("</CurrentDayDuration>")

    # Extract values
    current_download = int(data[download_start:download_end])
    current_upload = int(data[upload_start:upload_end])
    month_duration = int(data[duration_start:duration_end])
    last_clear_time = data[clear_time_start:clear_time_end]
    current_day_used = int(data[day_used_start:day_used_end])
    current_day_duration = int(data[day_duration_start:day_duration_end])

    # Calculate total data usage
    total_usage = current_download + current_upload
    usage_percentage = total_usage / data_limit * 100

    print(f"Total WiFi data usage: {total_usage / (1024 ** 3):.2f} GB ({usage_percentage:.2f}% of 300 GB monthly limit)")

    if usage_percentage >= threshold * 100:
        warning_message = f"*** Warning: You have used {usage_percentage:.2f}% of your 300 GB monthly data limit ***"
        print(warning_message)

        # Show Windows pop-up notification
        #        notification.notify(
        #            title="Data Usage Warning",
        #            message=warning_message,
        #            app_name="Data Usage Monitor",
        #            timeout=10  # Notification lasts for 10 seconds
        #        )

        # Use notify-send to create a pop-up notification
        #subprocess.run(['notify-send', 'Data Usage Warning', warning_message])
    else:
        print("WiFi data usage for the month is below the warning threshold of 80%, all good ✓")

    # Month and day statistics
    print(f"Data usage for the current day: {current_day_used / (1024 ** 3):.2f} GB")

    # Convert MonthDuration and CurrentDayDuration from seconds to a more readable format (hours, minutes)
    month_duration_readable = str(timedelta(seconds=month_duration))
    current_day_duration_readable = str(timedelta(seconds=current_day_duration))

    print(f"Total online time this month: {month_duration_readable}")
    print(f"Total online time today: {current_day_duration_readable}")
    print(f"Last data reset date: {last_clear_time}")
else:
    print(f"Failed to retrieve data usage statistics. Status code: {response.status_code}")
```

### Once-Per-Day Wrapper

To avoid hammering the router API or slowing down shell startup, I wrapped the script in a Bash check:

```bash
# ~/.bashrc
bash ~/scripts/WIFI.sh
```

Then inside [`WIFI.sh`](http://WIFI.sh):

```bash
#!/bin/bash

# Define the log file location
LOG_FILE="/tmp/wifi_last_run_time.log"

# Get today's date in YYYY-MM-DD format
TODAY=$(date +%F)

# Check if the log file exists; if not, create it
if [[ ! -f $LOG_FILE ]]; then
    touch $LOG_FILE
fi

# Read the last run date from the log file
LAST_RUN_DATE=$(cat $LOG_FILE)

# Check if the script has already been run today
if [[ "$LAST_RUN_DATE" == "$TODAY" ]]; then
    echo "WiFi usage for the month was already determined to be fine today ✓"
else
    # Run main script here
    rm /tmp/pythonoutfile2.log 2>/dev/null

python3 /home/rhayden/scripts/wifi_data_usage_checker.py > /tmp/pythonoutfile2.log ; echo
cat /tmp/pythonoutfile2.log | grep 'Warning\|reset\|usage' | grep -v current\ day ; echo
cal ; echo

    # Update the log file with today's date
    echo "$TODAY" > $LOG_FILE
fi
```

This makes sure it runs **once per day**, and prints a calendar after the results.

### Final Output (Sample):

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756371632627/90121b48-b5f4-40bb-afa5-8c362c01d6fe.png align="left")

```bash
Total WiFi data usage: 269.12 GB (89.71% of 300 GB monthly limit)
*** Warning: You have used 89.71% of your 300 GB monthly data limit ***
Data usage for the current day: 2.11 GB
Total online time this month: 210:03:12
Total online time today: 03:42:18
Last data reset date: 2025-07-01
```
