-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Joe Hancuff
committed
Sep 21, 2023
0 parents
commit f81e82b
Showing
2 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Pingy - The Rockstar of Ping | ||
|
||
Pingy is a Python-based application that visualizes ping latency over time. It's like watching the universe expand, but with more immediate feedback. | ||
|
||
## Features | ||
|
||
- Real-time ping latency visualization | ||
- Pause and resume functionality | ||
- Customizable ping intervals | ||
- CLI and GUI input options | ||
- Existential dread included for free | ||
|
||
## Installation | ||
|
||
### Script Version | ||
|
||
1. Clone the repository or download the `pingy.py` file. | ||
2. Install the required Python packages: | ||
``` | ||
pip install ping3 matplotlib | ||
``` | ||
3. Run the script: | ||
``` | ||
python pingy.py [host] | ||
``` | ||
### Stand-alone Executable Version | ||
1. Download the `pingy.exe` file from the releases section. | ||
2. Place within your system PATH and run from cli. | ||
3. Alternatively double-click to run. No installation required. | ||
## Usage | ||
### Script Version | ||
Run the script with an optional host argument: | ||
``` | ||
python pingy.py google.com | ||
``` | ||
Or without any arguments to be prompted for the host: | ||
``` | ||
python pingy.py | ||
``` | ||
### Stand-alone Executable Version | ||
Place executable in a folder that is within your system PATH environment variable and run `pingi.exe` from PowerShell or CMD. | ||
Alternatively, you can just double-click `pingi.exe` and it'll prompt you for a host or ip. | ||
## Contributing | ||
Feel free to fork, clone, and submit PRs. Or don't. The universe doesn't care. | ||
## License | ||
MIT License. Because even in a godless universe, we need rules. | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import tkinter as tk | ||
from ping3 import ping | ||
import matplotlib.pyplot as plt | ||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg | ||
from itertools import groupby | ||
from operator import itemgetter | ||
from tkinter import simpledialog | ||
import threading | ||
import collections | ||
import argparse | ||
import time | ||
|
||
# Initialize variables | ||
ping_times = collections.deque(maxlen=100) | ||
ping_status = collections.deque(maxlen=100) | ||
|
||
|
||
rolling_avg = 0 | ||
is_paused = False | ||
|
||
|
||
|
||
|
||
|
||
# Function to update the graph and labels | ||
def update(host): | ||
global rolling_avg, is_paused | ||
while True: | ||
if not is_paused: | ||
latency = ping(host, timeout=1) | ||
if latency is None or latency > 1: | ||
status_label.config(text="Status: Down", fg="red") | ||
ping_times.append(0) | ||
ping_status.append('down') | ||
else: | ||
latency_ms = latency * 1000 | ||
status_label.config(text="Status: Up", fg="green") | ||
ping_times.append(latency_ms) | ||
ping_status.append('up') | ||
|
||
|
||
if len(ping_times) > 0: | ||
rolling_avg = sum(ping_times) / len(ping_times) | ||
avg_label.config(text=f"Rolling Avg: {rolling_avg:.2f} ms", fg="white") | ||
|
||
ax.clear() | ||
x = list(range(len(ping_times))) | ||
heights = [1000 if status == 'down' else latency for latency, status in zip(ping_times, ping_status)] | ||
colors = ['red' if status == 'down' else 'green' for status in ping_status] | ||
ax.bar(x, heights, color=colors) | ||
|
||
|
||
# Add a red vertical span when the host is down | ||
down_indices = [i for i, status in enumerate(ping_status) if status == 'down'] | ||
def group_consecutive(lst): | ||
for _, group in groupby(enumerate(lst), lambda i_x: i_x[0]-i_x[1]): | ||
yield list(map(itemgetter(1), group)) | ||
|
||
ax.axvspan(start, end, color='red', alpha=0.5) | ||
|
||
ax.set_facecolor("black") | ||
ax.set_title(f'Ping Latency to {host} Over Time', color="white") | ||
ax.set_xlabel('Pings', color="white") | ||
ax.set_ylabel('Latency (ms)', color="white") | ||
|
||
ax.tick_params(axis='x', colors='white') | ||
ax.tick_params(axis='y', colors='white') | ||
canvas.draw() | ||
|
||
time.sleep(ping_interval.get() / 1000) | ||
|
||
# Pause and Play function | ||
def toggle_pause(): | ||
global is_paused | ||
is_paused = not is_paused | ||
pause_button.config(text="Pause" if not is_paused else "Play") | ||
|
||
# CLI Argument Parsing | ||
parser = argparse.ArgumentParser(description="Pingi - The Rockstar of Ping") | ||
parser.add_argument("host", nargs="?", help="The IP address or hostname to ping") | ||
args = parser.parse_args() | ||
|
||
if args.host is None: | ||
root = tk.Tk() | ||
root.withdraw() # Hide the main window | ||
args.host = simpledialog.askstring("Input", "No host provided. Please enter the IP address or hostname to ping:") | ||
root.destroy() # Destroy the main window | ||
|
||
if not args.host: | ||
print("You gotta give me something to work with! Exiting.") | ||
exit(1) | ||
|
||
|
||
# GUI setup | ||
root = tk.Tk() | ||
root.title(f"Pingi - Pinging {args.host}") | ||
root.configure(bg="black") | ||
root.resizable(False, False) | ||
ping_interval = tk.IntVar() | ||
ping_interval.set(250) # Default value | ||
frame = tk.Frame(root, bg="black") | ||
frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) | ||
|
||
status_label = tk.Label(frame, text="Status: Unknown", fg="white", bg="black") | ||
status_label.grid(row=0, column=0, sticky=tk.W) | ||
|
||
avg_label = tk.Label(frame, text="Rolling Avg: Unknown", fg="white", bg="black") | ||
avg_label.grid(row=1, column=0, sticky=tk.W) | ||
|
||
fig, ax = plt.subplots() | ||
fig.patch.set_facecolor("black") | ||
canvas = FigureCanvasTkAgg(fig, master=frame) | ||
canvas_widget = canvas.get_tk_widget() | ||
canvas_widget.grid(row=2, column=0) | ||
|
||
pause_button = tk.Button(frame, text="Pause", command=toggle_pause) | ||
pause_button.grid(row=3, column=0, sticky=tk.W) | ||
|
||
exit_button = tk.Button(frame, text="Exit", command=root.quit) | ||
exit_button.grid(row=3, column=1, sticky=tk.E) | ||
options = [250, 500, 750, 1000] | ||
interval_menu = tk.OptionMenu(frame, ping_interval, *options) | ||
interval_menu.grid(row=4, column=1, sticky=tk.W) | ||
interval_label = tk.Label(frame, text="Ping Interval (ms):", fg="white", bg="black") | ||
interval_label.grid(row=4, column=0, sticky=tk.E) | ||
# Start the update thread | ||
update_thread = threading.Thread(target=update, args=(args.host,)) | ||
update_thread.daemon = True | ||
update_thread.start() | ||
|
||
root.mainloop() |