loading...
Cover image for I Built a Bot to Try and Get Money Back From My Internet Provider

I Built a Bot to Try and Get Money Back From My Internet Provider

healeycodes profile image Andrew Healey Updated on ・4 min read

In my contract with my ISP, they gave me a range of speeds to expect but also a speed that was the guaranteed minimum. If they aren't able to keep above this minimum, I'm eligible for a discount a few times per year.

I didn't want to sit spamming speedtest.net to check when my speeds were getting low. I wanted to know if there had been dips. Were the dips at the same times? Was there a pattern? I needed data and some data visualization to know if/when I might be eligible for any discounts and whether it was worth pursuing.

Something like this

Bandwidth graph

Raspberry Pi

Running on my trusty Raspberry Pi. Powered via a USB cable from the router and connected via ethernet so the results (barring other network use) should be reliable.

Check out my current bandwidth results live or read the source code on GitHub.

Over-designed

I started this project off way too complicated. I used a web browser automation framework called Selenium to visit Netflix's fast.com bandwidth test to check my speed. It used a headless Chromium instance.

# wait for test to finish i.e. when 'your speed message' is shown
WebDriverWait(driver, 120).until(
    expected_conditions.presence_of_element_located(
        (By.CSS_SELECTOR, FAST_COMPLETE_CSS))
)

Not only was this quite brittle and vulnerable to CSS changes (which had to be hardcoded, see above) it also meant that any users of this project needed to get headless Chromium setup for Raspbian (the default Linux distro for Raspberry Pi). After troubleshooting this and getting it running, I realized it was over-designed.

Using this method remains an option in the project (browsertest.py) but it gives less accurate results on Raspberry Pis due to the browser overhead. Note: this project works on any platform but is mainly targetted towards Pis.

I discovered late in the game that speedtest.net have a great CLI library and I should have used it from the start. Here's how I get the download speed in clitest.py.

import speedtest

# ..

def get_speed():
    """
    Use Speedtest CLI to test bandwidth speed.
        :return: Download speed in Mbps
    """
    s = speedtest.Speedtest()
    s.download()
    results_dict = s.results.dict()
    return results_dict['download'] / 1048576  # convert bits to megabits

This script runs via crontab and is pointed at the server. A command similar to python clitest.py 'https://server-location/save' 'password' runs every half an hour. The Windows alternative is Task Scheduler but I believe it's clunkier.

Back-end

I thought it would be neat to be able to check my speeds from anywhere so I created a Glitch project to store, receive, and host the results. It's an Express/Node project that has two API routes.

Results are sent to /save along with a password, which is set via an environmental variable on Glitch.

A slice of results can be read from /read in JSON. Here's what the Express route for that looks like.

// get bandwidth test results for graphing here
app.get("/read", function(request, response) {
  const data = db.get("results").value();
  const prepared = data.map(s => {
    return { x: s.date, y: Number(s.speed).toFixed(3) };
  });
  const trimmed = prepared.slice(Math.max(prepared.length - 48, 1));
  response.send(trimmed); // send a slice of results
});

For storage, I wanted something that didn't require any setup at all. lowdb is a small local JSON database and it's perfect because there's only ever going to be one process reading or writing, and the write event occurs every half an hour or so. lowdb creates the 'database' file if it doesn't already exist.

Data visualization

Chart.js is the go-to library for graphs in JavaScript and uses the Canvas API. It's batteries-included and looks nice by default (but perhaps I'm just used to the style!). It's about fifty lines, including the API call.

fetch('/read')
    .then(response => response.json())
    .then(json => renderGraph(json));
const safeDate = time => new Date(parseInt(time)).toUTCString();
const renderGraph = (speedData) => {
    var ctx = document.getElementById('myChart').getContext('2d');
    var myChart = new Chart(ctx, {
    type: 'scatter',
    data: {
        datasets: [{
            data: speedData,
            backgroundColor: () => 'rgba(255, 99, 132, 0.2)',
            borderColor: () => 'rgba(255, 99, 132, 1)',
            borderWidth: 1,
            pointRadius: 5,
        }]
    },
    options: {
        scales: {
            xAxes: [{
                type: 'linear',
                position: 'bottom',
                ticks: {
                    userCallback: (label, index, labels) => safeDate(label)
                },
                scaleLabel: {
                    display: true,
                    labelString: 'Date'
                }
            }],
            yAxes: [{
                scaleLabel: {
                    display: true,
                    labelString: 'Mbps'
                },
                ticks: {
                    beginAtZero: true
                }
            }],
        },
        title: {
            display: true,
            text: 'Bandwidth Test Results'
        },
        legend: {
            display: false,
        },
        tooltips: {
            callbacks: {
                label: function(tooltipItem, data) {
                return `${tooltipItem.value} Mbps @ ${safeDate(tooltipItem.label)}`;
                }
            }
        }
    }
    });
}

I find it easy to play around with Chart.js and like JavaScript it's very productive if you want to throw something together. The docs are great and it's a large enough library that common searches will find helpful StackOverflow answers.

Where to go from here

So far my speeds have been hovering around the guaranteed minimum, usually dipping just under around 8pm local time. At current, I have no reason to complain! A pleasant surprise.

It will be straightforward to diagnose any future bandwidth problems as I now have an up-to-date record of my speeds. Hopefully, some of this project's code will help you diagnose any simple problems with your bandwidth throughout the day.


Join 150+ people signed up to my newsletter on programming and personal growth!

I tweet about tech @healeycodes.

Posted on by:

healeycodes profile

Andrew Healey

@healeycodes

📚 🌵 🐕 Love blogging, open-source, and helping out. https://healeycodes.com

Discussion

pic
Editor guide
 

Now we need some AI to read contracts and look for sweet bits of info like this!

 

Automate all the things! 😊

 

Absolutely! But actually a contract reading AI would be fantasticly useful and I would pay for that sort of service.

This would be tremendously empowering for marginalized communities that have historically received the short end of the stick when it comes to Ts&Cs. Could potentially be a powerful tool to democratize the legaleese.

I love this angle Phil, really interesting! It's so tempting to go away and build this, if anyone has a crack I'd love to checkout your work. I could imagine you would ask the AI for positive or negative traits within a document. How could this AI become a consumer product, some sort of Phone app. Perhaps it's more of an API like Amazon lex powers poly to make "Alexa".

 

I'm wonder how is the minimum guaranteed and compensated when your speed test depends on a 3rd party. The only way to 100% now what is your speed is to download/upload files from your ISPs servers and that is also not 100% concrete because the network could be fine but the host not. In other words, even if you found the dips manually or automated, doesn't your ISP have the best "get out of jail" free card in the world?

I'm not trying to undermine your effort I'm just wondering how does your ISP define minimum speed.

 

Hi Alex, that’s a great question.

I went and scanned the terms and conditions last night and the ISP have their own private speed test for their customers. It takes longer and is presumably logged on their end.

The result of their test matches the graph’s results.

My intentions with this project is for the graph to show me if I have any issues, and at what times, so that I can go and follow up in a more official manner.

I agree that they would not accept this graph as evidence.

 

This was niggling at me. Thanks for clarifying, and congratulations on a very cool project.

 

Admirable. If I understand correctly, does your isp publish their speed test results? Which country and ISP if in may ask? Is it a national regulation?

 

I've thought about doing this with Fios but never followed through. I got the idea from my first IT job where we requested refunds due to outages or low bandwidth supported by a Nagios graph. Did you have any positive results from reporting the slowness to your ISP? Getting a few bucks back off of them would be a good win and worth the setup time if you expanded it to email them with each dip below minimums.

 

It turns out that there weren't any problems with my bandwidth so I've had no contact.

If the graph showed a pattern, I would perform any official ISP speed-tests at the now-predictable slow parts.

I like that automation idea though. Perhaps a Twitter bot!

 

I like it!! Twitter is usually a good way to get the fast attention of customer support reps from bigger companies!

 

Nice! Is it worth being more unpredictable from their perspective? I might vary the interval or even just offset it a bit to come out of phase with itself day after day (every 29 mins instead of 30, let's say), as well as stick a VPN in there to ensure the ISP is not prioritizing speed test traffic. Varying the speed test host might not be a bad idea either if you can find others.

 

Every 29 minutes is a great idea!

Quite a few interesting ideas here. I know that speedtest-cli accepts --list which displays a list of speedtest.net servers sorted by distance. Presumably, there are further configuration options.

There are a few ways to make this project more real-world and reliable.

Thanks for the insightful comment.

 

Inspiring post, i have Raspberry Pi lying in my home. Going to implement this project. I also live in UK but which ISP provides this discount deal, from my experience i haven't heard about ISP offering discounts if the speed limit isn't consistent. Would love to get some discount since my internet tends to be slow quiet regularly.

 

My ISP requires you to run their speed test in order to be eligible for the discount. But this project might tell you at which times to run it.

My graph tends to dip in the afternoon until morning.

Let me know if you have any issues with the project! 😁

 

Hey Andrew, great article and great work on the tool, I'll have to get something similar setup soon! Just a couple of questions:

  1. Does this cause any dips in network speed when the test is running? I.e. do you feel the test running when you are browsing or doing other things on the internet, or is the test pretty quick to finish?
  2. Why did you opt for 30 minute intervals?
 

Either test doesn’t affect browsing, I've been playing games that rely on low latency and haven’t seen any spikes. On very slow connections (~5Mbps? Perhaps the test would be felt).

I felt that any speed issues that lasted shorter than half an hour would be ‘blips’ and I wouldn’t mind missing them. I haven’t put too much thought into the 30 minute timing interval.

Thanks for your questions! 😊

 

Interesting, do the UK ISPs consider third party data valid for the discount claims? I know ATT, Comcast and TW have a similar scheme in the US, but you have to provide results using the speed test mechanism on their website or built in to the router/gateway.

Either way, very cool project, thanks for sharing :)

 

I mentioned this in another comment, that the aim of this project is to serve as a kind of ‘bandwidth canary’ so that more official complaint steps can be taken.

I thought about automating the process with just my ISP but wanted to provide a more general tool 😊

Thanks!

 

This is the best thing I've read all day.

 

Very! Right down to the nice engineer who hooked up our line.

Here in the UK, ISPs tend to be quite customer-oriented (in my experience).

 

I know what I am doing saturday! :]

 

That is a great idea, pretty cool.

 

Thanks Daniel!

 

This is cool man,

 

Great! I'm writing my own in NodeJS.
I'll post my results here.

 

Thank you @healycodes, very inspiring! 🚀.

Here is the result, it's enhanced with a telegram bot, and send relevant notifications about changes in data points.
Bandwidth Checker and Logger built with NodeJS

 
 

This is so cool! thanks for sharing

 

Whoa this is interesting, gonna do this sooner or later

 

Idk if this will help you, but I use this CLI tool written in Go on Linux regularly. It is small and really convenient! github.com/ddo/fast/releases

 

I’ll check it out! Thanks for sharing it Vincent 👍🏻

 
 

Cool!! Nice idea for a side project this weekend. Thanks for sharing...

 

in my country , they will tell you in aggressive way ,How you can debunk our Service ???