-
Notifications
You must be signed in to change notification settings - Fork 0
/
speedtest_gui_2.py
226 lines (197 loc) · 7.87 KB
/
speedtest_gui_2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/usr/bin/env python3
"""
Name: speedtest_gui_2.py
Author: William A Loring
Created: 08/10/23
Purpose: Test internet upload and download bandwidth with customtkinter
Use threads for a responsive GUI while testing.
using Speedtest.net
https://github.com/sivel/speedtest-cli
https://pypi.org/project/speedtest-cli/
"""
# pip install customtkinter
import customtkinter as ct
# pip install speedtest-cli
from speedtest import Speedtest
import threading
class SpeedTestGui(ct.CTk):
# Define the initialize method
def __init__(self):
super().__init__()
self.title("Internet Speed Test")
self.geometry("375x275")
self.iconbitmap("speed.ico")
self.resizable(False, False)
# Modes: system (default), light, dark
ct.set_appearance_mode("dark")
# Themes: blue (default), dark-blue, green
ct.set_default_color_theme("blue")
# Bind the closing event to the on_closing function
self.protocol("WM_DELETE_WINDOW", self.quit)
# Create speedtest object
self.speedtest = Speedtest(secure=True)
# Call method to create all the widgets
self.create_widgets()
# ---------------------------------- START --------------------------------#
def start(self, *args):
"""Start a thread to perform the speed test
This runs the speedtest on its own thread and doesn't affect
the main program thread. The GUI is still responsive.
"""
test_thread = threading.Thread(target=self.run_speedtest)
test_thread.start()
# -------------------------- RUN SPEEDTEST --------------------------------#
def run_speedtest(self):
# Clear all labels
self.lbl_server.configure(text="")
self.lbl_download.configure(text="")
self.lbl_upload.configure(text="")
self.lbl_ping.configure(text="")
self.btn_start.configure(text="Testing . . .")
self.progress_bar.set(0)
# Call methods to run speed test
self.get_best_server()
self.get_download_bandwidth()
self.get_upload_bandwidth()
self.get_ping_latency()
# ---------------------- GET DOWNLOAD BANDWIDTH ---------------------------#
def get_download_bandwidth(self):
"""Get download bandwidth from test server"""
self.progress_bar.set(.33)
self.lbl_status.configure(text="Get Download Bandwidth . . .")
# Update the frame to show the label changes
self.main_frame.update()
# Get download bandwidth, returns bits per second
download_result = self.speedtest.download()
# Convert from bits per second to megabits per second
self._download_result = download_result / 1000 / 1000
self.lbl_download.configure(
text=f" {self._download_result:.2f} Mbps")
# Update the frame to show the label changes
self.main_frame.update()
# ---------------------- GET UPLOAD BANDWIDTH -----------------------------#
def get_upload_bandwidth(self):
"""Get upload bandwidth from test server"""
self.progress_bar.set(.66)
# Get and print upload speed
self.lbl_status.configure(text="Get Upload Bandwidth . . .")
self.main_frame.update()
# Get upload bandwidth, returns bits per second
upload_result = self.speedtest.upload()
# Convert from bits per second to megabits per second
self._upload_result = upload_result / 1000 / 1000
self.lbl_upload.configure(
text=f" {self._upload_result:.2f} Mbps")
# Update the frame to show the label changes
self.main_frame.update()
# -------------------------- GET PING LATENCY -----------------------------#
def get_ping_latency(self):
"""Get ping latency from test server"""
self.progress_bar.set(1)
# Get ping results/latency, return ms
self._ping_result = self.speedtest.results.ping
self.lbl_ping.configure(text=f" {self._ping_result:.2f} ms")
self.lbl_status.configure(text="Speed Test Complete")
self.btn_start.configure(text="Start Test")
# Update the frame to show the label changes
self.main_frame.update()
# ------------------------ GET BEST SERVER --------------------------------#
def get_best_server(self):
"""Return the nearest test server and location
in dictionary format"""
best_server = self.speedtest.get_best_server()
sponsor = best_server['sponsor']
name = best_server.get('name')
location = best_server.get('cc')
self.lbl_server.configure(text=f"{sponsor} - {name}, {location}")
# Update the frame to show the label changes
self.main_frame.update()
# ------------------------- CREATE WIDGETS --------------------------------#
def create_widgets(self):
self.main_frame = ct.CTkFrame(master=self)
# Fill the frame to the width of the window
self.main_frame.pack(fill=ct.X)
# Keep the frame size regardless of the widget sizes
self.main_frame.pack_propagate(False)
self.status_bar = ct.CTkFrame(master=self)
# Fill the frame to the width of the window
self.status_bar.pack(fill=ct.X)
# Keep the frame size regardless of the widget sizes
self.status_bar.pack_propagate(False)
self.lbl_status = ct.CTkLabel(
self.main_frame,
text=""
)
self.lbl_server = ct.CTkLabel(
self.main_frame,
text=""
)
self.lbl_download_label = ct.CTkLabel(
self.main_frame,
anchor=ct.E,
text="Download:",
width=13
)
self.lbl_upload_label = ct.CTkLabel(
self.main_frame,
anchor=ct.E,
text="Upload:",
width=13
)
self.lbl_ping_label = ct.CTkLabel(
self.main_frame,
anchor=ct.E,
text="Ping (Latency):",
width=13
)
self.lbl_download = ct.CTkLabel(
self.main_frame,
width=16,
text=""
)
self.lbl_upload = ct.CTkLabel(
self.main_frame,
width=16,
text=""
)
self.lbl_ping = ct.CTkLabel(
self.main_frame,
width=16,
text=""
)
self.btn_start = ct.CTkButton(
self.main_frame,
text="Start Test",
command=self.start
)
self.progress_bar = ct.CTkProgressBar(
self.status_bar,
mode="determinate",
width=375
)
self.progress_bar.set(0)
self.progress_bar.grid(row=0, column=0, columnspan=2, sticky=ct.W)
self.btn_start.grid(row=0, column=0, sticky=ct.W)
self.lbl_status.grid(row=0, column=1, sticky=ct.W)
self.lbl_server.grid(row=1, column=0, sticky=ct.W, columnspan=2)
self.lbl_download_label.grid(row=2, column=0, sticky=ct.EW)
self.lbl_upload_label.grid(row=3, column=0, sticky=ct.EW)
self.lbl_ping_label.grid(row=4, column=0, sticky=ct.EW)
self.lbl_download.grid(row=2, column=1, sticky=ct.W)
self.lbl_upload.grid(row=3, column=1, sticky=ct.W)
self.lbl_ping.grid(row=4, column=1, sticky=ct.W)
# Set padding between frame and window
self.main_frame.pack_configure(padx=20, pady=20)
# Set padding for all widgets
for child in self.main_frame.winfo_children():
child.grid_configure(padx=4, pady=4, ipadx=3, ipady=3)
# The enter key will activate the calculate method
self.bind("<Return>", self.start)
self.bind("<KP_Enter>", self.start)
self.bind('<Escape>', self.quit)
# ----------------------------- QUIT PROGRAM ------------------------------#
def quit(self, *args):
self.destroy()
# Create object from the program class
speed_test = SpeedTestGui()
speed_test.mainloop()