james-atkinson / speedcomplainer

A python app that will test your internet connection and then complain to your service provider (and log to a data store if you'd like)
509 stars 106 forks source link

Need help understanding "tweetThresholds" #16

Open ha1f3mpty opened 8 years ago

ha1f3mpty commented 8 years ago

First off, thanks for this and I do not have any issues with how this runs. I think i just need to have a better understanding. I have been able to successfully modify the config.json file to fit my needs with "tweetTo", "internetSpeed", and "tweetThresholds". I say successful because the thing sucessfully tweets the different messages. My "issue" is that it doesn't tweet the right message based on tweetThresholds, well not the one I expect.

Here is the scenario; the Internet through put I pay for is 100 Mbps / 10 Mbps down/up respectively. I set tweetThresholds of 10, 25, 50, and 80 which tweet out some words along with a hashtag of EpicFail, Fail, OK, and Congrats respectively. Lately my connection has been decent, between 60 and 79. I point out the 79 because my highest in the last 5 days was 79.92 all of which had the highest tweet of Congrats, which should be reserved for 80 Mbps and up. I also had a 5 day low of 56.14 Mbps and it also got the highest tweet of Congrats. It feels like no matter what the "internetSpeed" is at it tweets the highest level tweet. I modified the speedcomplainer script file to tweak the number of seconds that the complainer should tweet so it will be about 3.3 days between tweets. Any help is appreciated, below are the content of my files. I tried to use the insert code option but it still broke it up so I put it in just as text, sorry. I would have attached files but thats not an option.

Here is my config.json file with my twitter account specifics removed for privacy:

{

"twitter": {
    "twitterToken": "XXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "twitterConsumerKey": "XXXXXXXXXXXXXXXXXX",
    "twitterTokenSecret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "twitterConsumerSecret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"tweetTo": "@MediacomSupport",
"internetSpeed": "100",
"tweetThresholds": {
    "10": [
        "{tweetTo}, you have one job to do for me? I'm paying for {internetSpeed} Mbps but getting only {downloadResult} Mbps?!? Shame. #MediacomEpicFail"
    ],
    "25": [
        "{tweetTo}, what is going on? I expect better than {downloadResult} Mbps when I'm paying for {internetSpeed} Mbps. Fix your network! #MeiacomFail"
    ],
    "50": [
        "{tweetTo}, I guess {downloadResult} Mbps is better than nothing, I still expect closer to the {internetSpeed} Mbps I pay for. #MediacomOK"
    ],
    "80": [
        "{tweetTo}, look at you making good on your promiss of {internetSpeed} Mbps by giving me {downloadResult} Mbps. #CongratsMediacom"
    ]
},
"log": {
    "type": "csv",
    "files": {
        "ping": "pingresults.csv",
        "speed": "speedresults.csv"
    }
}

} `

And here is the speedcomplainer file:

import os import sys import time from datetime import datetime import daemon import signal import threading import twitter import json import random from logger import Logger

shutdownFlag = False

def main(filename, argv): print "======================================" print " Starting Speed Complainer! " print " Lets get noisy! " print "======================================"

global shutdownFlag
signal.signal(signal.SIGINT, shutdownHandler)

monitor = Monitor()

while not shutdownFlag:
    try:

        monitor.run()

        for i in range(0, 5):
            if shutdownFlag:
                break
            time.sleep(1)

    except Exception as e:
        print 'Error: %s' % e
        sys.exit(1)

sys.exit()

def shutdownHandler(signo, stack_frame): global shutdownFlag print 'Got shutdown signal (%s: %s).' % (signo, stack_frame) shutdownFlag = True

class Monitor(): def init(self): self.lastPingCheck = None self.lastSpeedTest = None

def run(self):
    if not self.lastPingCheck or (datetime.now() - self.lastPingCheck).total_seconds() >= (3600):
        self.runPingTest()
        self.lastPingCheck = datetime.now()

    if not self.lastSpeedTest or (datetime.now() - self.lastSpeedTest).total_seconds() >= (285120):
        self.runSpeedTest()
        self.lastSpeedTest = datetime.now()

def runPingTest(self):
    pingThread = PingTest()
    pingThread.start()

def runSpeedTest(self):
    speedThread = SpeedTest()
    speedThread.start()

class PingTest(threading.Thread): def init(self, numPings=3, pingTimeout=2, maxWaitTime=6): super(PingTest, self).init() self.numPings = numPings self.pingTimeout = pingTimeout self.maxWaitTime = maxWaitTime self.config = json.load(open('./config.json')) self.logger = Logger(self.config['log']['type'], { 'filename': self.config['log']['files']['ping'] })

def run(self):
    pingResults = self.doPingTest()
    self.logPingResults(pingResults)

def doPingTest(self):
    response = os.system("ping -c %s -W %s -w %s 8.8.8.8 > /dev/null 2>&1" % (self.numPings, (self.pingTimeout * 1000), self.maxWaitTime))
    success = 0
    if response == 0:
        success = 1
    return { 'date': datetime.now(), 'success': success }

def logPingResults(self, pingResults):
    self.logger.log([ pingResults['date'].strftime('%Y-%m-%d %H:%M:%S'), str(pingResults['success'])])

class SpeedTest(threading.Thread): def init(self): super(SpeedTest, self).init() self.config = json.load(open('./config.json')) self.logger = Logger(self.config['log']['type'], { 'filename': self.config['log']['files']['speed'] })

def run(self):
    speedTestResults = self.doSpeedTest()
    self.logSpeedTestResults(speedTestResults)
    self.tweetResults(speedTestResults)

def doSpeedTest(self):
    # run a speed test
    result = os.popen("/usr/bin/speedtest --simple").read()
    if 'Cannot' in result:
        return { 'date': datetime.now(), 'uploadResult': 0, 'downloadResult': 0, 'ping': 0 }

    # Result:
    # Ping: 529.084 ms
    # Download: 0.52 Mbit/s
    # Upload: 1.79 Mbit/s

    resultSet = result.split('\n')
    pingResult = resultSet[0]
    downloadResult = resultSet[1]
    uploadResult = resultSet[2]

    pingResult = float(pingResult.replace('Ping: ', '').replace(' ms', ''))
    downloadResult = float(downloadResult.replace('Download: ', '').replace(' Mbit/s', ''))
    uploadResult = float(uploadResult.replace('Upload: ', '').replace(' Mbit/s', ''))

    return { 'date': datetime.now(), 'uploadResult': uploadResult, 'downloadResult': downloadResult, 'ping': pingResult }

def logSpeedTestResults(self, speedTestResults):
    self.logger.log([ speedTestResults['date'].strftime('%Y-%m-%d %H:%M:%S'), str(speedTestResults['uploadResult']), str(speedTestResults['downloadResult']), str(speedTestResults['ping']) ])

def tweetResults(self, speedTestResults):
    thresholdMessages = self.config['tweetThresholds']
    message = None
    for (threshold, messages) in thresholdMessages.items():
        threshold = float(threshold)
        if speedTestResults['downloadResult'] < threshold:
            message = messages[random.randint(0, len(messages) - 1)].replace('{tweetTo}', self.config['tweetTo']).replace('{internetSpeed}', self.config['internetSpeed']).replace('{downloadResult}', str(speedTestResults['downloadResult']))

    if message:
        api = twitter.Api(consumer_key=self.config['twitter']['twitterConsumerKey'],
                        consumer_secret=self.config['twitter']['twitterConsumerSecret'],
                        access_token_key=self.config['twitter']['twitterToken'],
                        access_token_secret=self.config['twitter']['twitterTokenSecret'])
        if api:
            status = api.PostUpdate(message)

class DaemonApp(): def init(self, pidFilePath, stdout_path='/dev/null', stderr_path='/dev/null'): self.stdin_path = '/dev/null' self.stdout_path = stdout_path self.stderr_path = stderr_path self.pidfile_path = pidFilePath self.pidfile_timeout = 1

def run(self):
    main(__file__, sys.argv[1:])

if name == 'main': main(file, sys.argv[1:])

workingDirectory = os.path.basename(os.path.realpath(__file__))
stdout_path = '/dev/null'
stderr_path = '/dev/null'
fileName, fileExt = os.path.split(os.path.realpath(__file__))
pidFilePath = os.path.join(workingDirectory, os.path.basename(fileName) + '.pid')
from daemon import runner
dRunner = runner.DaemonRunner(DaemonApp(pidFilePath, stdout_path, stderr_path))
dRunner.daemon_context.working_directory = workingDirectory
dRunner.daemon_context.umask = 0o002
dRunner.daemon_context.signal_map = { signal.SIGTERM: 'terminate', signal.SIGUP: 'terminate' }
dRunner.do_action()
ghost commented 8 years ago

I have the same issue. I have three thresholds, listed in ascending order in the .json file, and the {downloadResult} mismatches to the threshold values and then 'tweets' the wrong message.

    },
    "tweetTo": "@telstra",
    "internetSpeed": "18",
    "tweetThresholds": {
        "4": [
           "{tweetTo} {downloadResult}Mbit/s? Please get me back up to speed ({internetspeed}Mbit/s)!"
        ],
        "12": [
            "{tweetTo} {downloadResult}Mbit/s is OK, but I would rather be getting the {internetSpeed}Mbit/s that I'm supposed to get"
        ],
        "16": [
            "{tweetTo} {downloadResult}Mbit/s vs. {internetSpeed}Mbit/s - nice job!"
        ]
    },
dmontenegro commented 8 years ago

Im having the same issue. The messages are not correct compare to the download result. Always is using the last one.

BraveH commented 7 years ago

Bump, you need to add a break inside this if statement:

if speedTestResults['downloadResult'] < threshold: message = messages[random.randint(0, len(messages) - 1)].replace('{tweetTo}', self.config['tweetTo']).replace('{internetSpeed}', self.config['internetSpeed']).replace('{downloadResult}', str(speedTestResults['downloadResult'])) break

BraveH commented 7 years ago

A smarter solution would actually be to have a min variable such that if you find a threshold value < minThreshold then you update the message object. minThreshold is initialized as 10000 or something. Therefore the code would look something like this:

minThreshold = 10000 if speedTestResults['downloadResult'] < threshold and threshold < minThreshold: minThreshold = threshold message = messages[random.randint(0, len(messages) - 1)].replace('{tweetTo}', self.config['tweetTo']).replace('{internetSpeed}', self.config['internetSpeed']).replace('{downloadResult}', str(speedTestResults['downloadResult']))