Skip to main content

Command Palette

Search for a command to run...

Monitoring Router Data Usage with Python (Linux & Windows)

Updated
•7 min read•View as Markdown

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. It exposes data usage stats at this endpoint:

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.

pip install plyer

Here’s the script:

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

Linux Version: Terminal-Only

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

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() if I want to hook in notify-send, but keep it disabled by default.


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:

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

Then inside WIFI.sh:

#!/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):

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

More from this blog

RH Scripts

16 posts