diff --git a/.github/screenshot.png b/.github/screenshot.png new file mode 100644 index 0000000..2c647e6 Binary files /dev/null and b/.github/screenshot.png differ diff --git a/.gitignore b/.gitignore index 894a44c..0a212a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# VS Code +.vscode/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ef48dcc --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +### Legend : +❌ Removed | ✔️ Added | 💫 Fixed | ✨ Improved + +## Version 0.1 - 29/05/19 +- ✔️ Upload monitor (Mbits/sec) +- ✔️ Download monitor (Mbits/sec) +- ✔️ Data consumed monitor (up & down) -> useful if you use your mobile data + +To close it, you need to close the terminal. \ No newline at end of file diff --git a/README.md b/README.md index d72ad1c..8ab876a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,28 @@ -# NetworkTracker -A simple python network tracker +# Bandwidth monitor +![Latest release](https://img.shields.io/github/release/N3ROO/BandwidthMonitor.svg) +![opissues](https://img.shields.io/github/issues/N3ROO/BandwidthMonitor.svg) +![clissues](https://img.shields.io/github/issues-closed/N3ROO/BandwidthMonitor.svg) + +A simple python bandwidth monitor (upload / download). + +![preview](.github/screenshot.png) + +## 1. Getting started +### 1.1 Prerequisites +- [psutil](https://psutil.readthedocs.io/en/latest/index.html?highlight=net_io_counters) + +### 1.2 How to use it +Run `python main.py`. + +### 1.3 Setting up your dev environment +Open the folder with your favorite code editor, and the job is done. Run `pyinstaller bandwidth_monitor.spec` to generate an executable. + +## 2. Miscellaneous +### 2.1 Changelog +The changelog is available [here](CHANGELOG.md). + +### 2.2 Authors +- **N3ROO** - *Initial work* - [Github](https://github.com/N3ROO) [Website](https://n3roo.github.io/) + +### 2.3 License +This project is licensed under the MIT license - see the [LICENSE](LICENSE) file for details \ No newline at end of file diff --git a/src/Tracker.py b/src/Tracker.py new file mode 100644 index 0000000..021b5d1 --- /dev/null +++ b/src/Tracker.py @@ -0,0 +1,73 @@ +import psutil +import time +from threading import Thread + + +# Index : number of bytes sent +__BYTES_SENT__ = 0 +# Index : number of bytes received +__BYTES_RECV__ = 1 +# Index : number of packets sent +__PACKETS_SENT__ = 2 +# Index : number of packets received +__PACKETS_RECV__ = 3 +# Index : total number of errors while receiving +__ERR_IN__ = 4 +# Index : total number of errors while sending +__ERR_OUT__ = 5 +# Index : total number of incoming packets which were dropped +__DROP_IN__ = 6 +# Index : total number of outgoing packets which were dropped +__DROP_OUT__ = 7 + + +class Tracker: + + def __init__(self): + self.__reset_bytes_recv_vars__() + self.__reset_bytes_sent_vars__() + self.init_total_sent = self.__get_bytes_sent_total__() + self.init_total_recv = self.__get_bytes_recv_total__() + + + def get_total_data_used(self): + """ Returns the data used since the start 4G/3G ... + """ + return ((self.__get_bytes_sent_total__() - self.init_total_sent) + + (self.__get_bytes_recv_total__() - self.init_total_recv)) + + + def get_current_upload_speed(self): + """ Returns the current upload speed in bytes per seconds. + """ + dtime = time.time() - self.last_bytes_sent_time + dsent = self.__get_bytes_sent_total__() - self.last_bytes_sent_total + self.__reset_bytes_sent_vars__() + return dsent / dtime if dtime != 0 else 0 + + + def get_current_download_speed(self): + """ Returns the current downlaod speed in bytes per seconds. + """ + dtime = time.time() - self.last_bytes_recv_time + dsent = self.__get_bytes_recv_total__() - self.last_bytes_recv_total + self.__reset_bytes_recv_vars__() + return dsent / dtime if dtime != 0 else 0 + + + def __reset_bytes_sent_vars__(self): + self.last_bytes_sent_total = self.__get_bytes_sent_total__() + self.last_bytes_sent_time = time.time() + + + def __reset_bytes_recv_vars__(self): + self.last_bytes_recv_total = self.__get_bytes_recv_total__() + self.last_bytes_recv_time = time.time() + + + def __get_bytes_sent_total__(self): + return psutil.net_io_counters(pernic=False)[__BYTES_SENT__] + + + def __get_bytes_recv_total__(self): + return psutil.net_io_counters(pernic=False)[__BYTES_RECV__] \ No newline at end of file diff --git a/src/bandwidth_monitor.py b/src/bandwidth_monitor.py new file mode 100644 index 0000000..9dad947 --- /dev/null +++ b/src/bandwidth_monitor.py @@ -0,0 +1,92 @@ +import logging +import time +import numpy +import matplotlib.pyplot as plt + +from Tracker import Tracker +from datetime import datetime + + +logger = logging.getLogger(__name__) +# Data shown on the plot represents the last 1 minutes +DATA_DURATION = 5 +# The data variable +speeds_recv = [] +speeds_sent = [] +times = [] + +def main(): + """ Executes the program. + """ + tracker = Tracker() + plt.ion() + last_total_data_used = 0 + + while True: + # Retrieve the up and down speeds + time.sleep(0.5) + down_speed = 8 * (tracker.get_current_download_speed() / (2**20)) + up_speed = 8 * (tracker.get_current_upload_speed() / (2**20)) + + # Store it + add_data(down_speed, up_speed) + + # Data used + total_data_used = round(tracker.get_total_data_used() / (2**20), 3) + write_data_used(last_total_data_used, total_data_used) + last_total_data_used = total_data_used + + # Update & display the plot + recv_curve, = plt.plot(times, speeds_recv) + sent_curve, = plt.plot(times, speeds_sent) + + plt.legend([recv_curve, sent_curve], ['Download', 'Upload']) + plt.ylabel('Mb/s', fontsize=8) + ax = plt.gca() + ax.tick_params(axis='x', labelsize=6) + ax.tick_params(axis='y', labelsize=6) + ax.get_figure().canvas.set_window_title('Internet speed - N3RO') + + plt.draw() + plt.pause(0.0001) + plt.clf() + + +def add_data(down_speed, up_speed): + if len(times) > 1: + if divmod((times[-1] - times[0]).total_seconds(), 60)[0] >= DATA_DURATION: + del times[0] + del speeds_recv[0] + del speeds_sent[0] + speeds_recv.append(down_speed) + speeds_sent.append(up_speed) + times.append(datetime.now()) + + +def write_data_used(last_total_data_used, total_data_used): + if total_data_used != last_total_data_used: + if total_data_used > last_total_data_used + 0.5: + print('!! ' + str(total_data_used) + ' Mo used.') + elif total_data_used > last_total_data_used + 1: + print('! ' + str(total_data_used) + ' Mo used.') + else: + print(str(total_data_used) + ' Mo used.') + + +if __name__ == '__main__': + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s ' + + '-- %(levelname)s ' + + '-- [%(filename)s:%(lineno)s ' + + '-- %(funcName)s() ] ' + + '-- %(message)s') + stream_handler = logging.StreamHandler() + stream_handler.setLevel(logging.DEBUG) + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) + + try: + main() + except Exception as e: + logger.exception('Unexpected error') \ No newline at end of file