File: D:/bin/scripts/python3.4/speedtest/speedtest.py
# (SS,17/4/21) run speedtest command line version and save results in MySQL database
# running commandline help from https://stackoverflow.com/questions/748028/how-to-get-output-of-exe-in-python-script
# Python 3 required
# https://stackabuse.com/pythons-os-and-subprocess-popen-commands/
import subprocess
#import os
import datetime
# following to get server name
import socket
# following for sleep/wait
import time
#import MySQLdb
# (SS,26/2/21) for Python 3, replaced above with following
import pymysql
import sys
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import email.utils
import json
def set_alert(AAlert):
global FAlert # required to modify a global
FAlert = AAlert
def get_alert():
return FAlert
# (SS,27/2/21)
def is_debug_mode():
return FDebugMode
def print_html_header():
print("""<html>
<title>Speedtest Result</title>
<style>
html, body, h1, h2, p {
font-family: Arial, Helvetica, sans-serif;
}
img {
border: 0;
}
table {
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
td, th {
padding: 5px;
white-space: nowrap;
}
</style>
<body>
""")
def print_html_footer():
print("""</body>
</html>""")
def print_html(AText):
print(AText + "<br>")
def print_debug(AText):
if FDebugMode:
print(AText)
def send_email_file(AFileName, ASubject, AFrom, ATo, ABcc):
# Open a plain text file for reading. For this example, assume that
# the text file contains only ASCII characters.
fp = open(AFileName, 'rb')
# Create a text/plain message
#msg = MIMEText(fp.read())
html = fp.read()
fp.close()
msg = MIMEMultipart('alternative')
# header
if get_alert():
msg['Subject'] = 'ALERT!!! ' + ASubject
else:
msg['Subject'] = ASubject
msg['From'] = AFrom
msg['To'] = ATo
msg['Date'] = email.utils.formatdate(localtime=True)
if get_alert():
msg['X-Priority'] = '2'
#* html = html.replace('\r\n', '<br>')
# (SS,27/2/21) added following to fix error in Python 3: AttributeError: 'bytes' object has no attribute 'encode'
html = html.decode("utf-8")
part1 = MIMEText(html, 'html')
msg.attach(part1)
# send the messsage using localhost
s = smtplib.SMTP('localhost')
s.sendmail(AFrom, [ATo, ABcc], msg.as_string())
s.quit()
def run_speedtest(ACount):
LStartTime = datetime.datetime.now()
LHostName = socket.gethostname()
# for home server use Server: ITPS Ltd - Newcastle Upon Tyne (id = 16353)
# for ITP server at UK Servers use Server: UK Dedicated Servers - London (id = 30376)
# ACount used as odd/even to switch between two different servers
if LHostName == 'otwwinwebsvr':
if (ACount % 2) == 0:
LServerID = '20746'
else:
LServerID = '16353'
else:
if (ACount % 2) == 0:
LServerID = '32944'
else:
LServerID = '30376'
print('For ' + LHostName + ' using server ID: ' + LServerID)
p = subprocess.Popen(['D:\Bin\Speedtest\speedtest.exe', '--format=json-pretty', '-s', LServerID], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
# following is for error test, forces error i.e. not such server
# p = subprocess.Popen(['D:\Bin\Speedtest\speedtest.exe', '--format=json-pretty', '-s', '4'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
out = p[0]
err = p[1]
if err == b'':
LResult = out
else:
LResult = err
print(LResult.decode("utf-8"))
# parse the JSON string
j = json.loads(LResult.decode("utf-8"))
# check type, and log
if 'type' in j:
LType = j["type"]
LTimestamp = j["timestamp"]
else:
# assume error if type missing
# i.e.
#{
# "error": "Cannot read: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\r\n"
#}
#Traceback (most recent call last):
# File "speedtest.py", line 247, in <module>
# run_speedtest(LCount)
# File "speedtest.py", line 154, in run_speedtest
# LType = j["type"]
#KeyError: 'type'
LType = "error"
if LType == "log":
LMessage = j["message"]
LLevel = j["level"]
LSQL = 'INSERT INTO log SET \
StartTime = "%s", \
EndTime = NOW(), \
SpeedtestTimestamp = "%s", \
Message = "%s", \
Level = "%s"' % (LStartTime.strftime('%Y-%m-%d %H:%M:%S'), LTimestamp, LMessage, LLevel)
cur.execute(LSQL)
elif LType == "error":
LMessage = j["error"]
LLevel = "error"
LSQL = 'INSERT INTO log SET \
StartTime = "%s", \
EndTime = NOW(), \
Message = "%s", \
Level = "%s"' % (LStartTime.strftime('%Y-%m-%d %H:%M:%S'), LMessage, LLevel)
cur.execute(LSQL)
elif LType == "result":
LInterfaceIsVPN = "1" if j["interface"]["isVpn"] else "0"
LDownloadMbps = str(round(j["download"]["bandwidth"] * 8 / 1E6, 2))
LUploadMbps = str(round(j["upload"]["bandwidth"] * 8 / 1E6, 2))
# if packet loss not set then set to NULL
if 'packetLoss' not in j:
LPacketLoss = 'NULL'
else:
LPacketLoss = j["packetLoss"]
LSQL = 'INSERT INTO results SET \
StartTime = "%s", \
EndTime = NOW(), \
DownloadMbps = %s, \
UploadMbps = %s, \
SpeedtestTimestamp = "%s", \
PingJitter = "%s", PingLatency = "%s", \
DownloadBandwidth = "%s", DownloadBytes = "%s", DownloadElapsed = "%s", \
UploadBandwidth = "%s", UploadBytes = "%s", UploadElapsed = "%s", \
PacketLoss = %s, isp = "%s", \
InterfaceInternalIP = "%s", InterfaceName = "%s", InterfaceMacAddr = "%s", InterfaceIsVPN = %s, InterfaceExternalIP = "%s", \
ServerID = "%s", ServerName = "%s", ServerLocation = "%s", ServerCountry = "%s", ServerHost = "%s", ServerPort = "%s", ServerIP = "%s", \
ResultID = "%s", ResultURL = "%s" \
' % (LStartTime.strftime('%Y-%m-%d %H:%M:%S'),
LDownloadMbps, LUploadMbps,
LTimestamp,
j["ping"]["jitter"], j["ping"]["latency"],
j["download"]["bandwidth"], j["download"]["bytes"], j["download"]["elapsed"],
j["upload"]["bandwidth"], j["upload"]["bytes"], j["upload"]["elapsed"],
LPacketLoss, j["isp"],
j["interface"]["internalIp"], j["interface"]["name"], j["interface"]["macAddr"], LInterfaceIsVPN, j["interface"]["externalIp"],
j["server"]["id"], j["server"]["name"], j["server"]["location"], j["server"]["country"], j["server"]["host"], j["server"]["port"], j["server"]["ip"],
j["result"]["id"], j["result"]["url"]
)
cur.execute(LSQL)
FAlert = False # global used to set alert
# (SS,31/7/17) added following for enter into debug mode, i.e. email not sent, info displayed on screen, certain things not rung
FDebugMode = True # False # False # True
if not FDebugMode:
LOG_FILE = 'speedtest.log'
else:
LOG_FILE = 'speedtest-debug.log'
# (SS,23/2/18) now getting all currencies in one go from XML file on European Central Bank website, via http://fixer.io/
#get_currencies_from_ecb()
# exit
#sys.exit(0)
# output all prints to file
f = open(LOG_FILE, 'w')
if not FDebugMode:
sys.stdout = f
start = datetime.datetime.now()
#print_html_header()
print_html('Started: ' + start.strftime('%Y-%m-%d %H:%M:%S'))
print_html('')
filename_date_suffix = start.strftime('%Y-%m-%d')
# (SS,26/2/21) for Python 3, replaced MySQLdb in following with pymysql
con = pymysql.connect(host='127.0.0.1', user='common', passwd='itpcommon123', db='speedtest')
cur = con.cursor()
# check_gpu_page('CUR', 'gbuk/rtx-3060-ti/components-upgrades/graphics-cards/324_3091_30343_xx_ba00013562-bv00313952/xx-criteria.html')
# run speedtest in D:\Bin\Speedtest\speedtest.exe
# repeat forever
LCount = 1
while True:
print("Running...")
run_speedtest(LCount)
LCount = LCount + 1
print("Waiting..." + str(LCount))
time.sleep(60 * 10)
print_html('')
cur.close()
con.close()
finish = datetime.datetime.now()
time_taken = finish - start
#print_html('')
print_html('Finished: ' + finish.strftime('%Y-%m-%d %H:%M:%S'))
print_html('Time taken: %0.3f seconds' % (time_taken.seconds + time_taken.microseconds / 1E6))
#print_html_footer()
# set back to default out and close the opened log file
if not FDebugMode:
sys.stdout = sys.__stdout__
f.close()
#except: # catch *all* exceptions
# print_html("Error: " + str(sys.exc_info()[0]))
# set_alert(True)
# send the file as an email
# only send email if not in debug mode and alert set
if not FDebugMode and get_alert():
send_email_file(LOG_FILE, 'Speedtest Result', 'gpucheck@ssbsoft.co.uk', 'surinder@ssbsoft.co.uk', 'srinda@gmail.com')