Runs a speed test and tweets at Comcast/Xfinity if it’s slower than what you pay for. Logs results locally too. Set your speed targets, plug in your API keys, and let it call them out.

import os
from pathlib import Path
from datetime import datetime, timezone
from dotenv import load_dotenv
import speedtest
import twitter


def run_speed_test() -> tuple[float, float]:
    s = speedtest.Speedtest()
    s.get_best_server(s.set_mini_server(os.getenv("SPEEDTEST_SERVER_URL", "http://stosat-nash-01.sys.comcast.net/")))
    s.download()
    s.upload()
    results = s.results.dict()
    download = results["download"] / 1_000_000
    upload = results["upload"] / 1_000_000
    return download, upload


def post_to_twitter(message: str) -> None:
    api = twitter.Api(
        consumer_key=os.getenv("CONSUMER_KEY"),
        consumer_secret=os.getenv("CONSUMER_SECRET"),
        access_token_key=os.getenv("ACCESS_TOKEN_KEY"),
        access_token_secret=os.getenv("ACCESS_TOKEN_SECRET"),
    )
    api.PostUpdate(message)


def log_speeds(download: float, upload: float, log_path: Path) -> None:
    timestamp = datetime.now(timezone.utc).astimezone().isoformat()
    with log_path.open("a") as f:
        f.write(f"{timestamp} - Download speed: {download:.2f}, Upload speed: {upload:.2f}\n")


def main() -> None:
    load_dotenv()

    paid_download = 1000.0
    paid_upload = 30.0
    location = os.getenv("LOCATION", "Knoxville, TN")
    log_path = Path("/var/log/speeds.log")

    try:
        download, upload = run_speed_test()
    except Exception as e:
        print(f"Speedtest failed: {e}")
        return

    paid_down_str = f"{int(paid_download)}down"
    paid_up_str = f"{int(paid_upload)}up"

    message = (
        f"Hey @Comcast @ComcastCares @xfinity why is my internet speed "
        f"{download:.2f}down/{upload:.2f}up when I pay for {paid_down_str}/{paid_up_str} in {location}?"
    )

    if download < paid_download or upload < paid_upload:
        try:
            post_to_twitter(message)
        except Exception as e:
            print(f"Twitter post failed: {e}")
        print(message)

    try:
        log_speeds(download, upload, log_path)
    except Exception as e:
        print(f"Logging failed: {e}")


if __name__ == "__main__":
    main()