Raspberry Pi Internet Speed Monitor

In this Raspberry Pi internet speed monitor tutorial, we will be showing you how you can set up your Raspberry Pi to monitor your internet connection and save the data to view in Grafana or Google Drive.

 Raspberry Pi Internet Speed Monitor

This tutorial is great if you’re interested in monitoring how your download speed, upload speed, and ping are affected over time.

Additionally, this can help you work out what times your network may be at its peak capacity or if you’re suffering from a degraded internet connection.

To achieve this internet speed monitor, we will be showing you how to write a small Python script that interacts with a program called Speedtest CLI from Ookla.

Speedtest CLI is what our internet speed monitor will use to monitor the internet connection.

This program works by polling the popular speedtest.net service to get your ping, download speed, and upload speed.

If you would prefer to have a more full featured speed test tracker, we recommend following our speedtest Docker guide instead. This will give you a fancy web interface you can use to view your results and still allow integration with InfluxDB.

Equipment List

Below are all the pieces of equipment that we made use of to set up our Raspberry Pi internet speed monitor.

Recommended

Optional

Video Tutorial

You can watch the video below to learn how to set up an internet speed monitor on the Raspberry Pi.

Alternatively check out the written version of the guide in the next section.

Adblock removing the video? Subscribe to premium for no-ads.

Installing the Speedtest CLI

1. Before we get started with setting up the Raspberry Pi to monitor the internet’s speed, we must first make sure our Raspberry Pi is up to date.

We can update the Raspberry Pi by running the following two commands within the terminal.

sudo apt-get update
sudo apt-get upgrade

2. We now need to install some packages so that we can add the package repository for the Speedtest CLI software.

Run the following command to install gnupg1, apt-transport-https, dirmngr and lsb-release to your Raspberry Pi.

sudo apt install apt-transport-https gnupg1 dirmngr lsb-release

The apt-transport-https package is used to add support for the https protocol to the apt package manager. Without it apt will throw errors when connecting to Ookla’s package repository.

Additionally we also install gnupg1, this package is used for secure communication between your Raspberry Pi and the Speedtest.net servers.

We then install the dirmngr package. This package is utilized for handling the addition of the package repository to your Raspberry Pi’s sources list.

Finally, the last package we install is called “lsb-release“. We utilize this package to grab the operating systems release name.

3. With the packages we need installed we can now add the GPG key for Ookla’s Speedtest repository to the keychain.

We need this keychain to be able to download the speedtest command line interface to our Raspberry Pi.

curl -L https://packagecloud.io/ookla/speedtest-cli/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/speedtestcli-archive-keyring.gpg >/dev/null

4. Next we need to add the Ookla repository to our sources list.

Without adding the repository we won’t be able to install the Speedtest CLI to our Raspberry Pi.

You can add this repository by running the following command.

echo "deb [signed-by=/usr/share/keyrings/speedtestcli-archive-keyring.gpg] https://packagecloud.io/ookla/speedtest-cli/debian/ $(lsb_release -cs) main" | sudo tee  /etc/apt/sources.list.d/speedtest.list

Within this command, you will notice we use “$(lsb_release -cs)“. This bit of text allows us to insert the release name for our installation of Raspberry Pi OS directly into the command.

5. As we added a new package repository we need to update our package list.

Updating the package list is as simple as running the following command.

sudo apt update

6. Finally, we can install the official Speedtest CLI to our Raspberry Pi from Ookla.

Use the following command to install the package to your device.

sudo apt install speedtest

6. We can now test that we have installed the speedtest software to your Raspberry Pi.

Let us run the following command to start up the speedtest.

speedtest

When you first run the speedtest software on your Raspberry Pi you will be asked to agree to some terms and conditions.

To proceed passed this warning all you need to do is type in “YES” followed by the ENTER key.

Writing our Speed Test Python Script

1. Now that we have Speedtest CLI installed on the Raspberry Pi, we can now proceed to write our Python script that will continually monitor our download and upload speeds.

We can begin creating our Python script for the Raspberry Pi internet speed monitor by running the following command.

cd ~
nano speedtest.py

2. Within this file write the following lines of code. We will explain each important section of the code, so you get an idea of how everything works.

3. These four lines define all of the libraries that we will be relying on in our script. Below we will explain how each of these libraries will be is used.

import os: The os library is used by the script to interact with the operating system itself.

For this script, we will be using this library to check if a file exists.

import re: The re library allows us to easily do regular expressions by providing a library for handling pattern searches.

We use this to find our wanted values out of the data given to us from the Speedtest CLI.

import subprocess: The subprocess library is essential to this script, as we require it to be able to call another python script.

In our case, we will be using the subprocess library so we can launch up the Speedtest CLI software and retrieve the values returned by it.

import time: We utilize the time library so that we can record both the date and time for each call to the Speedtest CLI software.

This library is what will allow us to track our speed over a length of time.

import os
import re
import subprocess
import time

4. In this line of code, we utilize the subprocess library to launch a call to the Speedtest CLI and tell it to pipe everything from speedtest to stdout.

By using stdout.read().decode('utf-8') at the end of the call we store the response from the Speedtest CLI to our response variable and decode it to being a useable Python string.

response = subprocess.Popen('/usr/bin/speedtest --accept-license --accept-gdpr', shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')

5. These three lines of code are fairly simple, and all do the same thing.

They use the re library to run a regular expression for a certain piece of text and find the number located next to each piece of text.

For instance, the search for ping finds “Latency: 47.943 ms” but only grabs the number that is between the text.

ping = re.search('Latency:\s+(.*?)\s', response, re.MULTILINE)
download = re.search('Download:\s+(.*?)\s', response, re.MULTILINE)
upload = re.search('Upload:\s+(.*?)\s', response, re.MULTILINE)
jitter = re.search('Latency:.*?jitter:\s+(.*?)ms', response, re.MULTILINE)

6. These lines are important as we use the “.group()” function to grab the correct numbers from our regular expressions.

Using this we will get the values we are after from the output of the Speedtest CLI software that we can write to our CSV file.

ping = ping.group(1)
download = download.group(1)
upload = upload.group(1)
jitter = jitter.group(1)

7. This bit of code is straightforward. The code is kept within a try statement so that if any errors occur, it will not stop the script from operating.

Within the try statement, we first open up a call to our speedtest.csv file. Please note you may need to adjust the directory. Our code assumes that your user is called “pi“.

By using, “a+” in the arguments, we tell it that we want to create the file if it doesn’t exist, and that any new data should be appended to whatever is already in there.

Afterward, we utilize the os library to check our speedtest.csv files actual size in bytes.

If the file’s bytes is equal to 0, we go ahead.

If the file does exist, we proceed on as normal.

Ensure that you replace the placeholder “<USERNAME>” with your username.

try:
    f = open('/home/<USERNAME>/speedtest/speedtest.csv', 'a+')
    if os.stat('/home/<USERNAME>/speedtest/speedtest.csv').st_size == 0:
            f.write('Date,Time,Ping (ms),Jitter (ms),Download (Mbps),Upload (Mbps)\r\n')
except:
    pass

8. Finally, we print out all our data separated by commas.

We use the time library’s strftime() function to insert both the current date and the current time into our formatted string.

After that, we insert our ping, download, and upload.

f.write('{},{},{},{},{},{}\r\n'.format(time.strftime('%m/%d/%y'), time.strftime('%H:%M'), ping, jitter, download, upload))

9. Below we have an included an example of what the output data will look like on the first run of our code.

Date,Time,Ping (ms),Jitter (ms),Download (Mbps),Upload (Mbps)
04/29/21,06:28,18.32,1.21,23.30,7.78

10. Once you have finished writing your code, it should end up looking like what we have displayed below.

Remember that you must replace “<USERNAME>” with your username. For example, if your username was “pimylifeup” you would use “/home/pimylifeup/speedtest/speedtest.csv” within this script.

import os
import re
import subprocess
import time

response = subprocess.Popen('/usr/bin/speedtest --accept-license --accept-gdpr', shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')

ping = re.search('Latency:\s+(.*?)\s', response, re.MULTILINE)
download = re.search('Download:\s+(.*?)\s', response, re.MULTILINE)
upload = re.search('Upload:\s+(.*?)\s', response, re.MULTILINE)
jitter = re.search('Latency:.*?jitter:\s+(.*?)ms', response, re.MULTILINE)

ping = ping.group(1)
download = download.group(1)
upload = upload.group(1)
jitter = jitter.group(1)

try:
    f = open('/home/<USERNAME>/speedtest/speedtest.csv', 'a+')
    if os.stat('/home/<USERNAME>/speedtest/speedtest.csv').st_size == 0:
            f.write('Date,Time,Ping (ms),Jitter (ms),Download (Mbps),Upload (Mbps)\r\n')
except:
    pass

f.write('{},{},{},{},{},{}\r\n'.format(time.strftime('%m/%d/%y'), time.strftime('%H:%M'), ping, jitter, download, upload))

11. You can now save the file by pressing CTRL + X then Y and finally press ENTER.

12. With our script now written we need to make a folder where our speedtest.csv file will be stored. Run the following command to create this folder.

mkdir ~/speedtest

13. Now that we have made the required folder, we can go ahead and test the script.

We can test our script by running the following command.

python3 ~/speedtest.py

14. Once the script has finished executing you can then check out the results by opening up the newly created speedtest.csv.

Let’s open up this file by running the following command on the Raspberry Pi.

nano ~/speedtest/speedtest.csv

15. Within this file, you should see something like what we have below. The column headers and some rows of data.

Date,Time,Ping (ms),Jitter (ms),Download (Mbps),Upload (Mbps)
04/29/21,06:28,18.32,1.21,23.30,7.78

There are two different ways you can take this guide.

You can either use InfluxDB and Grafana to store and graph your data, or make use of gDrive to sync your data to Google Drive.

Using Grafana to Display your Speedtest Data

In this section, we will be showing you how you can use Grafana to graph your speed test data quickly.

Setting up InfluxDB for our Internet Speed Monitor

Before you start this section of this internet speed monitor tutorial, you will need to make sure you have installed InfluxDB V1 to your Raspberry Pi or on a separate server.

We will be using this as a place to store the data that our internet speed monitor receives.

1. To start, we need to go ahead and run the following command to start up the InfluxDB command-line tool.

We will be using this tool to create a database where we will store our data.

influx -username admin -password <password>

If you haven’t set up authentication, then you don’t need to worry about specifying the username and password to connect to InfluxDB.

2. Let’s now create a database called “internetspeed“.

Creating a database within InfluxDB is easy as using CREATE DATABASE followed by the database name.

CREATE DATABASE internetspeed

3. Our next step is to create a user called “speedmonitor” that we will be using to interact with our database.

Make sure that you swap out the password “pimylifeup” with something a bit more secure.

Don’t worry about privileges as we will be handling that in the next step.

CREATE USER "speedmonitor" WITH PASSWORD 'pimylifeup'

4. Now assign the new “speedmonitor” user all privileges to our “internetspeed” database.

GRANT ALL ON "internetspeed" to "speedmonitor"

5. With the database created, quit out of the tool by using the following command.

quit

6. The last thing we need to do is install the Python library we need to interact with our Influx database.

sudo apt install python3-influxdb

Saving our Speed Monitor Data to our InfluxDB

1. Now that we have our InfluxDB database created, let’s begin adding data into it by creating a new Python script.

This script will be similar to the one we created earlier, so we will only explain the new things that we are doing.

rm ~/speedtest.py
nano ~/speedtest.py

2. To start off this file, we need to import all the Python libraries we need.

import re
import subprocess
from influxdb import InfluxDBClient

As you can see, we have removed both the “os” and “time” libraries.

Both of these libraries are no longer needed as we don’t need to interact with files, and Influx automatically timestamps data.

We now import the “InfluxDBClient” client, which we will be using to interact with our InfluxDB server.

3. Our next step after importing packages is to call the Speedtest CLI and process the data.

By the end of this code block, we will have just the data that we are after.

response = subprocess.Popen('/usr/bin/speedtest --accept-license --accept-gdpr', shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')

ping = re.search('Latency:\s+(.*?)\s', response, re.MULTILINE)
download = re.search('Download:\s+(.*?)\s', response, re.MULTILINE)
upload = re.search('Upload:\s+(.*?)\s', response, re.MULTILINE)
jitter = re.search('Latency:.*?jitter:\s+(.*?)ms', response, re.MULTILINE)

ping = ping.group(1)
download = download.group(1)
upload = upload.group(1)
jitter = jitter.group(1)

4. Now here is where things get a little bit different. We need to format that data into a Python dictionary.

The reason for this is that the library expects the data to be in a JSON like format.

speed_data = [
    {
        "measurement" : "internet_speed",
        "tags" : {
            "host": "RaspberryPiMyLifeUp"
        },
        "fields" : {
            "download": float(download),
            "upload": float(upload),
            "ping": float(ping),
            "jitter": float(jitter)
        }
    }
]

Here we set up our dictionary with how InfluxDB expects the data. We gave the measurement a name, “internet_speed“.

We also set a tag called “host” to allow us to separate this out if we decide to handle multiple devices in the same database.

Next, we pass in the fields, which is the download speed, upload speed and ping that we retrieved in the previous bit of code.

We wrap our download, upload and ping variables in the float() function to convert them from a string to a number.

If we don’t use the float() function, Grafana will see these as strings and not interpret them correctly.

5. With all the data we need now on hand, we can now proceed to start using InfluxDB.

The first thing we need to do is to instantiate the InfluxDBClient library and pass in our connection details.

We only pass in the first five parameters for this function, the host, port, username, password, and database name.

If you want to see what data can be set, then you can view the official InfluxDB Python documentation.

client = InfluxDBClient('localhost', 8086, 'speedmonitor', 'pimylifeup', 'internetspeed')

If you are using an InfluxDB server that is not located on your Raspberry Pi, make sure you switch “localhost” with its IP address.

Also, you will need to change “pimylifeup” to the password that you set up earlier in the guide.

6. With a connection now made to our InfluxDB server, we can now write our data point to the server by adding the following line of code.

client.write_points(speed_data)

7. That is all we need to do to pass data to InfluxDB.

When you have finished typing in all the code the file, it should end up looking like what we have below.

import re
import subprocess
from influxdb import InfluxDBClient

response = subprocess.Popen('/usr/bin/speedtest --accept-license --accept-gdpr', shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')

ping = re.search('Latency:\s+(.*?)\s', response, re.MULTILINE)
download = re.search('Download:\s+(.*?)\s', response, re.MULTILINE)
upload = re.search('Upload:\s+(.*?)\s', response, re.MULTILINE)
jitter = re.search('Latency:.*?jitter:\s+(.*?)ms', response, re.MULTILINE)

ping = ping.group(1)
download = download.group(1)
upload = upload.group(1)
jitter = jitter.group(1)

speed_data = [
    {
        "measurement" : "internet_speed",
        "tags" : {
            "host": "RaspberryPiMyLifeUp"
        },
        "fields" : {
            "download": float(download),
            "upload": float(upload),
            "ping": float(ping),
            "jitter": float(jitter)
        }
    }
]
client = InfluxDBClient('localhost', 8086, 'speedmonitor', 'pimylifeup', 'internetspeed')

client.write_points(speed_data)

8. Save the file by pressing CTRL + X, followed by Y, then ENTER.

Viewing our Internet Speed Data in Grafana

Our next step is to get this database to show up in Grafana.

Before beginning this section, you must make sure that you have Grafana set up on your Raspberry Pi or a separate device.

Grafana is the tool that we will be using to graph and visualize all our data.

1. Once you have Grafana set up, you can proceed on with this tutorial by opening up its web interface.

If you are unsure where this sits, then go to your Raspberry Pi’s or server’s IP address, followed by the port :3000.

IPADDRESS:3000

2. Within the Grafana web interface, we need to add a new data source.

You can do this by hovering over the cog in the sidebar (1.), followed by the “Data Sources” menu option (2.).

Adding a new data source to Grafana

3. In the next menu, you will need to click the “Add data source” button to proceed.

Add Data Source to Grafana Configuration Page

4. On the “Add data source” page, you need to find InfluxDB, hover over it and click the “Select” button.

Add InfluxDB Time series database to Grafana

5. Now we are required to enter the details of your InfluxDB installation.

First, enter the URL for InfluxDB (1.). In our case, this is on the same Raspberry Pi that we are running the software on. If you are doing the same, then use the following URL.

http://localhost:8086

Next, we will need to enter all the details for our database (2.).

If you have followed our guide exactly, the Database should be set to “internetspeed“.

The User should be “speedmonitor”, and finally, the password should be the one you specified, if you used our example one this password would be “pimylifeup“.

Once you have set all the required information, click the “Save & Test” button (3.) located at the bottom of the screen.

Add InfluxDB Details for Grafana

6. The next step is to create a dashboard to display this data.

Hover over the addition icon (+) in the sidebar and click the “Dashboard” option.

Creating a Dashboard in Grafana

6. Over the “New Panel“, click the “Add Query” button.

Add Query to Dashboard

7. We can now set up the graph to read from our database.

Clickselect measurement” (1.) then select our measurement name, which in this case is “internet_speed” (2.)

Select Measurement to query

8. With the measurement set, we now need to set the field data we want to obverse.

Click the text “value” next to the field (1.). From here, select either “download“, “ping” or “upload“.

For this guide, we will be starting with “download” (2.).

Select Field to Display

9. Next, we want to make Grafana treat each result as a distinct individual result.

We can do this by clicking the addition (+) button in the select row (1.).

In the pop-up menu, hover over “Aggregations” and clickdistinct” (2.).

Change data aggregation

10. Finally, let’s give this data a better name so that we can understand it easier.

Set the alias of each of the fields to represent what they contain (1.). For example, with the download speed, we set the name “Download Speed“.

Now click the “Add Query” button (2.) and repeat steps 79 until you have all three fields (download, upload, and ping) added to the graph.

Set Data Alias for Measurement

11. Once you have added each field to the graph, click the spanner and cog symbol in the sidebar.

Configure Grafana Panel

12. In the “Title” option (1.) type in what you want to be displayed above the graph. In this example, we used the title “Network Speed“.

Once that is done, save the dashboard by clicking the save button (2.) in the top right-hand corner of the screen.

Set Panel Name for Grafana

13. Give a name to your dashboard (1.). This name can be anything you want. We called our “Network Speed Monitor“.

Now you save this new dashboard by clicking the “Save” button (2.).

Save Grafana Dashboard

14. With everything done, you should now be able to see your data displayed in a nice graph.

Internet Speed Monitor Dashboard Ready

Automating your Speed Monitor script with Grafana

Automating your script so that it runs periodically is a reasonably straightforward process.

1. The easiest way to automate your script to run every so often is to make use of the crontab.

You can modify the crontab by running the following command on your Raspberry Pi.

crontab -e

If you are asked what editor you want to use, we recommend you select nano as its the easiest to use.

2. Within this file, add the following cronjob to the bottom.

This cronjob will run every 30 minutes. If you want to work out a different timing, we recommend that you make use of our Crontab generator.

*/30 * * * * python3 /home/<USERNAME>/speedtest.py

As you can see, this is an effortless way of getting your internet speed tested regularly and not require you to run the script manually.

3. Once done, you can save the file by pressing CTRL + X, then Y, followed by ENTER.

The crontab will automatically be updated and will begin to run your script immediately.

Uploading your Internet Speed Data to Google Drive

In this section, we will be showing you how you can automatically sync your data with your Google Drive account.

Uploading Speed Test Data to Google Drive

1. Before you begin this section, you must have completed our compiling and running gDrive guide.

We will be using that software to complete the following steps.

2. With gDrive setup on your Raspberry Pi, we can now prepare it for our speed test data.

Let’s start by using gDrive to create a new folder on your Google Drive to store our speedtest.csv file.

We can do that by using the following command within the terminal.

gdrive mkdir speedtest

This command will show you a message saying the directory was created. This message will also show you an ID.

We will need this ID for our next few steps, so write it down somewhere safe.

3. With the folder now created, we can use its ID to upload a file to it.

For this test, we will be uploading our speedtest.csv file.

Run the following command and make sure you replace YOUR_FOLDER_ID with the id you retrieved in the previous step.

gdrive sync upload ~/speedtest YOUR_FOLDER_ID

On the initial sync, you should see a message like below appear on the command line.

This message tells you that the file has been successfully synced to your Google Drive account.

Starting sync...
Collecting local and remote file information...
Found 1 local files and 0 remote files

1 remote files are missing
[0001/0001] Uploading speedtest.csv -> speedtest/speedtest.csv
Sync finished in 3.119979351s

4. With Google Drive now successfully syncing with the Raspberry Pi, we can move onto automating the whole process so that we upload the speedtest.csv every time we edit it.

Automating the Raspberry Pi Internet Speed Monitor for Google Drive

1. The next big thing to do with your Raspberry Pi Internet Speed Monitor is to automate it.

To do the automation, we will be writing a simple bash script. This script will be called by crontab so that it will be run routinely.

Begin writing the bash script by running the following Linux command on your Raspberry Pi.

nano ~/speedtest.sh

2. Within this file, we want to enter the following lines.

Make sure that you replace “YOUR_FOLDER_ID” with the ID that you received when you created the folder on Google drive.

#!/bin/bash
python3 /home/<USERNAME>/speedtest.py
/usr/local/bin/gdrive sync upload  /home/<USERNAME>/speedtest YOUR_FOLDER_ID

3. Now save the file by pressing CTRL + X then Y and then finally ENTER.

4. Before we set up the crontab for our bash script, we must first give the script execution privileges.

We can achieve this by running the following command within the terminal.

sudo chmod +x ~/speedtest.sh

5. Now with everything done, we can finally move onto setting up the crontab.

Begin editing the crontab by running the following command on your Raspberry Pi. If you are asked what editor you want to use, we recommend you select Nano (Typically number 2).

crontab -e

6. Add the following line at the bottom of the file. This line will tell crontab that it should run our bash script once every hour.

If you want to change the behavior of the crontab, you can look at our Crontab generator to work out your desired values.

0 * * * * /home/<USERNAME>/speedtest.sh

7. You should now have your speed test monitor up and running with the script updating your speedtest.csv file on an hourly basis.

We hope by the end of this Raspberry Pi internet speed monitor tutorial you should now have your Raspberry Pi automatically running internet speed tests on your connection and uploading that data to Google on an hourly basis.

If you have any thoughts, feedback or anything else, then be sure to leave a comment below.

Leave a Reply

Your email address will not be published. Required fields are marked *

211 Comments

  1. Avatar for Adam
    Adam on

    Emmet hi,

    is there a way to add the jitter into this aspect of the coding for InfluxDB?

    While I did follow your tutorial and configured it without Jitter which works fine, I’m working if or is there a way to add it in this coding for my InfluxDB database so I can graph it on Graphana?

    [[[ — SNIPPED — ]]]
    Thanks,

    Adam

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Adam,

      Sorry for the late reply, but I have re-adjusted the tutorial so that Jitter is now included in all parts, including sending data to InfluxDB.

      Let me know if everything works correctly for you.

      Cheers,
      Emmet

  2. Avatar for Hendrik Koopmans
    Hendrik Koopmans on

    Thanks a lot, another great instruct-able.
    I used it for speedtest, influxDB and Grafana.
    For the latter the GUI has changed a bit, but it was easy manageable.

    Liebe Grüsse Henk

  3. Avatar for Christopher
    Christopher on

    Thank you for this excellent tutorial!

    I see that the speedtest also gives “jitter” as an output. It looks like this:
    Output
    Latency: 0.76 ms (0.22 ms jitter)

    I am not so good with regular expressions, but is there a way to extract the jitter value as well? I guess the following would need to be adapted:
    jitter = re.search(‘Latency:\s+(.*?)\s’, response, re.MULTILINE)

    Christopher

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Christopher,

      If you want to retrieve the jitter then you could use a line like this.

      jitter = re.search('\((.*?)\s.+jitter\)\s', response, re.MULTILINE)

      A full version of the script with the jitter added would look like something we have below.

      import os
      import re
      import subprocess
      import time
      
      response = subprocess.Popen('/usr/bin/speedtest', shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
      
      ping = re.search('Latency:\s+(.*?)\s', response, re.MULTILINE)
      download = re.search('Download:\s+(.*?)\s', response, re.MULTILINE)
      upload =  re.search('Upload:\s+(.*?)\s', response, re.MULTILINE)
      jitter = re.search('\((.*?)\s.+jitter\)\s', response, re.MULTILINE)
      
      ping = ping.group(1)
      download = download.group(1)
      upload = upload.group(1)
      jitter = jitter.group(1)
      
      try:
          f = open('/home/pi/speedtest/speedtest.csv', 'a+')
          if os.stat('/home/pi/speedtest/speedtest.csv').st_size == 0:
                  f.write('Date,Time,Ping (ms),Jitter (ms),Download (Mbps),Upload (Mbps)\r\n')
      except:
          pass
      
      f.write('{},{},{},{},{},{}\r\n'.format(time.strftime('%m/%d/%y'), time.strftime('%H:%M'), ping, jitter, download, upload))

      Cheers,
      Emmet

  4. Avatar for Martin
    Martin on

    Great tutorial Gus! I installed this on a 3B+ and I am very much impressed with the tutorial itself and the results it is giving me. Much kudos for putting it together!

    A couple of tips I found useful after after having played with it though.
    Speedtest does a check and picks whatever the fastest server is before running it’s test and this can lead to some random results. I have found adding a switch to use a specific server all of the time leads to more consistent results.
    speedtest -L will give you a list of the closest servers to you with their id number and to set a specific one add -s after the speedtest call in speedtest.py on line 4
    e.g.
    response = subprocess.Popen(‘/usr/bin/speedtest -s 5443’

    While I was playing with the above and tweaking a few other things I found that it had skewed my history so to get a clean slate I cleared the old results with the following command:
    influx -username admin -password
    use internetspeed
    delete * from “internet_speed” where time > 0

    Hopefully someone can find that useful 🙂

  5. Avatar for kubik256
    kubik256 on

    Your tutorial works excelent!
    I’ve add lost packets to loging values and it’s realy great, thank you 🙂

    HINT: For packet loss remove percent sign like this:
    float(badpackets[:-1]),

  6. Avatar for Pierre
    Pierre on

    Hello,

    Thank you for all, great !!
    For all people who have problem with crontab, use this:

    sudo crontab -e -u pi

    (this is the crontab of pi user, not root; and speedtest is intalled for pi user, not root)

  7. Avatar for UTCreeper
    UTCreeper on

    Thanks for this!!
    I was having rather low (200mbps-ish) results with this test method on an Rpi 4 – while I got consistent 900+ using the Ookla Official cli client (https://www.speedtest.net/apps/cli -> Debian/Ubuntu install directions.)
    Semi-easy, I installed that client, got the old one out of the bash auto-complete, and poof.. errors about not being able to Float the string. Fine, the results from the official client are different than the python one with “–simple”, so it’s a parsing issue. Three days of drinking and googling later, (more drinking than googling, thanks 2020v2!) I got the official client results dropping into Influx as the rest of the script expects. Still 99% your work/guide, but here it is for anyone else having trouble with the unofficial client, and better results with the Official client:

    response = subprocess.Popen(‘/usr/bin/speedtest’, shell=True, stdout=subprocess.PIPE).stdout.read().decode(‘utf-8’)
    p = re.search(‘Latency:\s+(.*?)\s’, response, re.MULTILINE)
    d = re.search(‘Download:\s+(.*?)\s’, response, re.MULTILINE)
    u = re.search(‘Upload:\s+(.*?)\s’, response, re.MULTILINE)

    ping = p.group(1)
    download = d.group(1)
    upload = u.group(1)

    Hope that helps, and thanks again for the guide!

    1. Avatar for Emmet
      Emmet on
      Editor

      HI UTCreeper,

      Thank you for pointing out the official Ookla client. Had honestly somehow completely missed that.

      I have updated the tutorial to utilize the official client, using the improvements that you worked out.

      Cheers,
      Emmet

    2. Avatar for MTR
      MTR on

      Thanks for the update!
      What steps do I need to take to update my existing installation to the Ookla Official client?

      Best regards

    3. Avatar for Emmet
      Emmet on
      Editor

      Hi MTR,

      You would need to remove the existing client that we installed during the original installation method.

      So that should be one of the following commands depending if you are running off Python 2 or 3.

      sudo pip3 uninstall speedtest-cli

      After that you can follow the updated “Installing the Speedtest CLI” section”.

      As well as the updated “Writing our Speed Test Python Script” section. (You can probably skip to step 3 of that section and just copy the new version of the script.

      Cheers,
      Emmet

    4. Avatar for MTR
      MTR on

      Thank you for the quick feedback!
      I have executed this so. In Grafana I do not get an update of the data. Either the script is not running autom. or it is running and not saving the results.
      When I run it manually, I have an entry in Grafana again.
      Are the instructions regarding the cronjob still correct?

    5. Avatar for MTR
      MTR on

      I think it is because the data is not written to InfluxDB via the script.

      Saving our Speed Monitor Data to our InfluxDB
      When I search the Raspberry Pi for “speedtest.py” I find only one file and it is stored under home/pi.
      If I now at step 1 execute
      rm ~/speedtest.py, won’t the file created in the section “Writing our Speed Test Python Script” be deleted again?
      As I understood it, a new, additional file must be created at “Saving our Speed Monitor Data to our InfluxDB”. Right?

      When I run rm ~/speedtest.py, I get the following prompt:
      rm ~/speedtest.py
      rm: remove regular file (read-only) ‘/home/pi/speedtest.py’?

    6. Avatar for Emmet
      Emmet on
      Editor

      Hi MTR,

      Yes if you are using this alongside InfluxDB then you need to follow the “Saving our Speed Monitor Data to our InfluxDB” section.

      That section has also been updated with the new code.

      When prompted to delete the file all you need to do is press Y then ENTER.

      Cheers,
      Emmet

    7. Avatar for Michael Auslander
      Michael Auslander on

      Thank you so much for this. I’m now getting very accurate results.

    8. Avatar for MTR
      MTR on

      Hy Emmet

      Thanks for your feedback and help.
      It was due to the cronjob. It was not executed for the affected user. I was able to correct this and now everything works smoothly.

  8. Avatar for Tim
    Tim on

    This is a great resource, thank you for a detailed explanation.

    I have installed it on two different PI 4s with 8MB. One using Wifi and the other wired. On the wired installation, I am getting different speed results when I run the script from the command line vs the cron job. Any ideas why? I have a 200MB internet connection. The manual run is consistent at 200, the cron job is consistent at 150.

  9. Avatar for norman
    norman on

    Many thanks for this tutorial. I am a complete novice at this sort of stuff but enjoy the challenge. Up and running on my Pi4 using Grafana.

  10. Avatar for David
    David on

    Easily the best guide I’ve ever followed!! I killed several hours trying to get another auto speedtest working, and when I finally did, was disappointed with the results.
    Because I currently have a Pi 3’s (limited to 330mb/sec), I created an ubuntu VM on my mac and got this running on that VM easily, thanks to this guide.

    Now I can present facts to my cable company about perfomance on their gigabit service.

  11. Avatar for Seb M
    Seb M on

    That did it, syncs on its own now. Thank you.

  12. Avatar for Seb M
    Seb M on

    Thank you for this brilliant guide (and the accompanying gDrive guide, which is slightly outdated due to changes in the Google website). One note: I was unable to use the “./gdrive” commands, instead I simply used “gdrive”.

    I have the speedtest up and running automatically, however it will not upload to Google Drive after each test. Instead, I must connect via SSH and activate the upload as per your guide. If I run the script with “sh speedtest.sh”, it functions correctly, so I am totally lost as to why it won’t do that automatically. Do you have any ideas? I was considering splitting it into two scripts that run slightly delayed to check whether the issue is due to an overlap of resources or similar.

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Seb,

      Glad to hear that for the most part things have worked well for you. I’ll try to get around to correcting the compiling gDrive guide to refelct thel atest changes in Googles website.

      Thank you also for pointing out the problem with ./gdrive, this was a leftover tid bit from the original version of this guide so I have corrected that now.

      When it comes to the gDrive problem, the first thing to try is to modify the speedtest.sh script.

      Change the third line, the one reference gdrive to the following. Basically all we are doing is modifying it so it references to the absolute path of where the gdrive binary is.

      /usr/local/bin/gdrive sync upload  /home/pi/speedtest YOUR_FOLDER_ID

      Let me know if that sorts out the issue that you are running in to.

      Cheers,
      Emmet

  13. Avatar for Brad Olson
    Brad Olson on

    This is probably the best instructional I’ve ever used! Everything went exactly as how you said, I was able to follow along, and when something went wrong, I could back up and find where I missed a step. Well done! Thank you!

  14. Avatar for Andrew
    Andrew on

    I sent a comment a couple of days ago saying that I was getting a bad gateway error when setting up Grafana. I finally worked out what I was doing wrong – I failed to follow the tutorial! At step 5, I saw that http://localhost:8086 was already shown, but in grey, so I did not type it in. Newbie error.

    In the meantime I have updated to Grafana 7. Some of the screens shown in the tutorial have been rearranged a little since version 6.

    Thanks for the tutorial!

    1. Avatar for TC
      TC on

      Thank you for this info. I was having the same newbie error…

  15. Avatar for Jim
    Jim on

    Good morning. I would like to keep an eye on my internet speeds and this is a very easy step-by-step process. Thank you for that.

    Unfortunately, I am getting an error, as below. Do you have any idea about how to fix it?

    FYI: My Pi is also running PiHole.

    Thanks.

    jim@raspberrypi:~ $ python3 ~/speedtest.py
    Traceback (most recent call last):
    File “/home/jim/speedtest.py”, line 23, in
    f.write(‘{},{},{},{},{}\r\n’.format(time.strftime(‘%m/%d/%y’), time.strftime (‘%H:%M’), ping, download, upload))
    NameError: name ‘f’ is not defined

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Jim,

      Looks like you are not using the default pi user which would likely be causing the error that you are seeing.

      Typically that happens when the script is unable to open / create the required file.

      All you should need to do is replace /pi/ with /jim/.

      So the following.

          f = open('/home/pi/speedtest/speedtest.csv', 'a+')
          if os.stat('/home/pi/speedtest/speedtest.csv').st_size == 0:

      Would become

          f = open('/home/jim/speedtest/speedtest.csv', 'a+')
          if os.stat('/home/jim/speedtest/speedtest.csv').st_size == 0:

      Cheers,
      Emmet

  16. Avatar for Glenn
    Glenn on

    Hi, I am trying to use the gdrive option. Is there any sort of fix yet? It was so very handy previously when I had it running, but I have thesame issue as Phillip below.
    Thanks for the tutorial, it is brilliant 🙂

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Glenn,

      The new solution should fix this.

      Follow the new “Uploading your Internet Speed Data to Google Drive” section.

      This section will get you to compile gDrive with your own Google API keys which should fix most of the issues that have been reported.

      Cheers,
      Emmet

  17. Avatar for Phillip Dunn
    Phillip Dunn on

    Hi
    I can’t get past the ./gdrive list step. When I try to login to my GoogleDrive acct I get a message Sign in with Google temporarily disabled for this app
    This app has not been verified yet by Google in order to use Google Sign In.

    Any tips?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Phillip,

      There is currently a problem with the gdrive app that we are providing for the tutorial.

      We are currently considering on whether to fix the app or move to using something like InfluxDB and Grafana instead.

  18. Avatar for Waqar
    Waqar on

    I have this running but now want to disable it, no idea how I do it. I also have Pihole running on the same pi so do not want to interfere with that

    1. Avatar for Gus
      Gus on
      Editor

      Assuming you have set up the cron. All you need to do is remove the line we entered into the crontab file. Repeat steps five and six in the “Automating” section, but instead of adding the line, simply remove it.

  19. Avatar for Krishan Mistry
    Krishan Mistry on

    Hi

    Can you change the script to run every minute?

    Thanks in advanced

    1. Avatar for Gus
      Gus on
      Editor

      Hi Krishan,

      You can use our cron job tool to calculate this for you.

      * * * * * /home/pi/speedtest.sh

      Keep in mind the script might not complete within a minute so you could end up with multiple instances running.

  20. Avatar for Carl S
    Carl S on

    I have tried everything and can not seem to get realistic speeds. They match my Pi running speed test on a browser at 50-70mb download.

    When I run it on windows I get 120-140mb which is inline with the specs.. I have disconnected USB ports and tried numerous switches.

    Any ideas? I am about ready to buy a Pi 4 and see if that fixes it. This is a part of a solution I am building and it all works but it is apparently an incorrect. Speed. For my network for wired Ethernet.

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Carl,

      The ethernet on the Raspberry Pi 3B+ is limited by the USB bus at 330mbit a second, you are likely running into that cap. The Raspberry Pi 3 and earlier are capped even lower due to the ethernet standard they implement.

      You should see much better ethernet speeds with a Raspberry Pi 4 as it has proper circuitry setup to handle the full gigabit speed of its ethernet connector.

      Cheers,
      Emmet

    2. Avatar for Theodore
      Theodore on

      Aha! This is what I was looking for!
      My Router is limiting the speed of the pi to 100 Mbmps, despite it being connected by ethernet cable. Makes the project redundant for my use-case (getting back at the ISP) but your tutorial was nothing short of perfect!
      Thank you so much!