From 9e84f7958402d862370ac9e2a81e91bc73b9149a Mon Sep 17 00:00:00 2001 From: Jonas_Jones <91549607+J-onasJones@users.noreply.github.com> Date: Mon, 20 Jun 2022 20:44:10 +0200 Subject: [PATCH] start of v0.2 --- README.md | 2 + arduino/arduino.ino | 9 ++ pc/main.py | 111 +--------------- pi-master/main.py | 312 +++++--------------------------------------- pi-slave/main.py | 82 ++++-------- 5 files changed, 75 insertions(+), 441 deletions(-) create mode 100644 arduino/arduino.ino diff --git a/README.md b/README.md index dd7060d..c5fa205 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# WARNING: This file is outdated. Since the last commit, a lot has changed. + # PI-MC-WATCHER A system that allows Monitoring of Raspberry PI('s) and it's running Minecraft Server(s) on PC and Mac as well as controlling their cooling diff --git a/arduino/arduino.ino b/arduino/arduino.ino new file mode 100644 index 0000000..95c2b6e --- /dev/null +++ b/arduino/arduino.ino @@ -0,0 +1,9 @@ +void setup() { + // put your setup code here, to run once: + +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/pc/main.py b/pc/main.py index 38689d2..747f341 100644 --- a/pc/main.py +++ b/pc/main.py @@ -1,105 +1,6 @@ -VERSION = "0.1.1" - -from ftplib import FTP -from io import BytesIO -from time import sleep, time - -launch_time = time() - -print("Starting PI-MC-WATCHER v" + VERSION + " for PC and Mac") -print("Initializing...") - -# wehther or not to print the stats to the console -print_stats = True - -# The credentials for the ftp server. These must be tweaked. -hostname = "172.24.1.193" -username = "testuser" -password = "uwu" - -# defining the name of the file the stats are saved to -filename = "output.txt" - -print("Connecting to FTP server...") - -ftp = FTP(hostname, username, password) -ftp.encoding = "utf-8" - -print("Connected!") - -start_time = time() - -print("All setup!") - -# permits user to read console logs from above. Can be removed to accelerate start. -sleep(3) - -while True: - - with open(filename, "wb") as file: - # use FTP's RETR command to download the file - ftp.retrbinary(f"RETR {filename}", file.write) - - file = open(filename, 'r') - content = file.read() - content = content.split(";") - # it is possible for the program to fetch the output text file right inbetween when the program on the Master PI cleared it and before it writes the stats. - # This sends an error message in the rare case of this occuring. - try: - fanmode = content[0] - slave_fanmode = content[1] - fanspeed = content[2] - fanspeed2 = content[3] - thermal = content[4] - slave_thermal = content[5] - cpu_usage = content[6] - cpu_freq = content[7] - cpu_up = content[8] - total_ram = content[9] - ram_usage = content[10] - ram_free = content[11] - ram_percent = content[12] - swap_percent = content[13] - disk_percent = content[14] - - mc_motd = content[15] - mc_version = content[16] - mc_players_max = content[17] - mc_players_on = content[18] - mc_version_brand = content[19] - mc_plugins = content[20] - mc_playerlist = content[21] - except: - # The error message to display if the above explained happens - print("WARNING: Couldn't read the file's data. If this doesn't happen a lot, just ignore this warning.") - - - if print_stats: - print("---------- Uptime: " + str(cpu_up) + " ----------") - # loop_time and stop_time won't be available on the first run as they haven't been measured yet. Therefore this fallback is needed. - try: - print("Loop time:\t" + str(round(loop_time, 2)) + "\ts") - print("CMD Uptime:\t" + str(round(stop_time - launch_time, 2)) + "\ts") - except: - print("Loop time:\t--.--\ts") - print("CMD Uptime:\t--.--\ts") - print("CPU") - print("\tusage:\t" + str(cpu_usage) + "\t%") - print("\tfreq:\t" + str(cpu_freq) + "\tMHz") - print("\ttemp:\t" + str(thermal) + "\tC") - print("RAM") - print("\tusage:\t" + str(ram_percent) + "\t%") - print("\tswap :\t" + str(swap_percent) + "\t%") - print("Disks") - print("\tusage:\t" + str(disk_percent) + "\t%") - print("FANMODE") - print("\tmain:\t" + str(fanmode) + "\t%") - print("\tslave:\t" + str(slave_fanmode) + "\t%") - print("\tglobal:\t" + str(fanspeed) + "\t%") - print("\t2ndary:\t" + str(fanspeed2) + "\t%") - - sleep(2) - - stop_time = time() - loop_time = stop_time - start_time - start_time = time() \ No newline at end of file +# Purpose: +# - When Arduino connected: +# - Communicate to Arduino over serial (tweak settings and get system monitor) +# - When Internet connected: +# - Communicate to RPI 4B over Wifi (tweak settings and get system monitor) +# - Neat UI with graphs, settings, etc... \ No newline at end of file diff --git a/pi-master/main.py b/pi-master/main.py index d3f12f3..e948b22 100644 --- a/pi-master/main.py +++ b/pi-master/main.py @@ -1,283 +1,33 @@ -VERSION = "0.1.1" +# Purpose: +# - transmit the following to Arduino using binary: +# - uptime +# - cpu usage (core #0 - #3) +# - cpu frequency +# - cpu temps (RPI 4) +# - cpu temps (RPI 1.2) +# - ram usage +# - am capacity +# - swap usuage +# - disk usage +# - disk capacity +# - disk used +# - mc server motd +# - mc sever version +# - mc server version brand +# - mc server players max +# - mc server players online +# - mc server plugins +# - mc server player_list +# - amount of connected devices +# - fan speed 180mm fan +# - fan speed 40mm fan -from http import server -import RPi.GPIO as GPIO -import subprocess, os, time, psutil +# - receive the following from the Arduino: +# - connected pc (can only be one) +# - used current of RPI 4 +# - used current of RPI 1.2 +# - requested fan curve -launch_time = time.time() - -# Wether or not to print system essential stats into the console (This can have a small to medium performance impact.) -print_stats = True -# Wehter or not to ignore the slave PI. This can be useful if no second PI is connected. -ignore_slave = True - -# Starting Messages -print("Starting PI-MC-WATCHER v" + VERSION + " for RPi") -print("Processing first loop. Each loop takes 5 seconds...") -print("\n") -if print_stats: - print("The system essential stats will be printed into the console. (This can be disabled at line 8 in the program file)") -else: - print("The system essential stats will NOT be printed into the console. (This can be enabled at line 8 in the program file)") - -print("\n") - -if ignore_slave: - print("Slave will be ignored. (This can be configured at line 10 in the program file)") -else: - print("Slave will NOT be ignored. (This can be configured at line 10 in the program file)") - -# Program Delay to allow reading the above printed messages -time.sleep(5) -print("\nStarting process MAIN") - -# GPIO setup -GPIO.setmode(GPIO.BCM) -GPIO.setwarnings(False) - -# Powering Status Pin to indicate that control program is up -GPIO.setup(4, GPIO.OUT) -GPIO.output(4, True) - -# setting up communication pins for binary fanmode transmission -GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) -GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) - -# setting up control pin for fancontrol -GPIO.setup(4, GPIO.OUT) - -# setting up power pin for second fancontrol -GPIO.setup(25, GPIO.OUT) - -# define default variables -> fan speed will be at max. if someting goes wrong with getting cpu temps -global thermal, fanmode, slave_fanmode, slave_thermal, i, file, cpu_usage, cpu_freq, cpu_up, total_ram, ram_usage, ram_free, ram_percent, swap_percent, disk_percent, mc_motd, mc_version, mc_players_max, mc_players_on, mc_version_brand, mc_plugins, mc_player_list -thermal = -99 -fanmode = 100 -i = 0 - -file_path = "/home/testuser/output.txt" - -file = open(file_path, 'w') -file.close() - -cpu_usage = 0 -cpu_freq = 0 -cpu_up = 0 -total_ram = 0 -ram_usage = 0 -ram_free = 0 -ram_percent = 0 -swap_percent = 0 -disk_percent = 0 - -# check mc server status too. Set to False to disable Minecraft server module -check_mcserver = True -mc_ip = "127.0.0.1" -mc_port = "25565" - -mc_motd = "-" -mc_version = 0 -mc_players_max = 0 -mc_players_on = 0 -mc_version_brand = "-" -mc_plugins = [] -mc_player_list = [] - -# function to get cpu temperature on linux and macOS and decide on fan speed. -def temp(thermal, fanmode): - thermal = int(round(float(subprocess.check_output("cat /sys/class/thermal/thermal_zone0/temp", shell=True).rstrip())/1000,2)) - thermal = int(thermal) - if thermal <= 20: - fanmode = 0 - elif 20 < thermal <= 35: - fanmode = 25 - elif 35 < thermal <= 50: - fanmode = 50 - elif 50 < thermal <= 65: - fanmode = 75 - elif 65 < thermal: - fanmode = 100 - return thermal, fanmode - -# function to round values -def display(val): - return round(float(val),2) - -# function to get system informations -def sys_monitor(cpu_usage, cpu_freq, cpu_up, total_ram, ram_usage, ram_free, ram_percent, swap_percent, disk_percent): - #cpu_usage = str(round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline()),2)) - cpu_usage = psutil.cpu_percent(interval=None) - cpu_freq = psutil.cpu_freq(percpu=False) - cpu_freq = cpu_freq.current - cpu_up = psutil.cpu_times() - cpu_up = cpu_up.user - - ram = psutil.virtual_memory() - #total_ram = str(round(display(subprocess.check_output("free | awk 'FNR == 2 {print $2/1000000}'", shell=True)))) - total_ram = ram.total - #ram_usage = int(subprocess.check_output("free | awk 'FNR == 2 {print $3/($3+$4)*100}'", shell=True)) - ram_usage = ram.used - #ram_free = str(100 - display(ram_usage)) - ram_free = ram.free - ram_percent = ram.percent - - swap = psutil.swap_memory() - swap_percent = swap.percent - - disk = psutil.disk_usage('/') - disk_percent = disk.percent - - - return cpu_usage, cpu_freq, cpu_up, total_ram, ram_usage, ram_free, ram_percent, swap_percent, disk_percent - -# function to get server status if enabled -def mcserver(mc_motd, mc_version, mc_players_max, mc_players_on, mc_version_brand, mc_plugins, mc_player_list): - if check_mcserver: - # importing module mcstatus --> must be installed for this in order to work - from mcstatus import MinecraftServer - mcserver = MinecraftServer.lookup(mc_ip + ":" + mc_port) - try: - status = mcserver.status() - mc_motd = status.description - mc_version = status.version.name - mc_players_max = status.players.max - mc_players_on = status.players.online - except: - status = "offline" - mc_motd = "-" - mc_version = "-" - mc_players_max = "-" - mc_players_on = "-" - - # IMPORTANT! - # for the following code to work, the query must be enabled in the server config file ('server.properties' --> 'enable-query=True'). - # If you don't have access to that file but still want your server status, you can delete the following lines that contain the 'query' argument. - # This will provide you with a more limited status: - # the version brand (vanilla, fabric modded, bukkit, etc.), the plugin list (if any) and the list if players won't be visible in that case - try: - query = mcserver.query() - mc_version = query.software.version - mc_version_brand = query.software.brand - mc_plugins = query.software.plugins - mc_player_list = query.players.names - except: - query = "unreachable" - mc_version = "-" - mc_version_brand = "-" - mc_plugins = "-" - mc_player_list = "-" - - # if no query --> delete 'mc_version_brand', 'mc_plugins' and 'mc_player_list' from the return argument - # the line below should then look like THIS: return mc_motd, mc_version, mc_players_max, mc_players_on - return mc_motd, mc_version, mc_players_max, mc_players_on, mc_version_brand, mc_plugins, mc_player_list - - -while True: - start_time = time.time() - # execute temperature function - - thermal, fanmode = temp(thermal, fanmode) - # determine fanmode of 2nd raspberry PI and guess CPU temps - if GPIO.input(17) == GPIO.HIGH and GPIO.input(18) == GPIO.HIGH: - slave_fanmode = 75 - slave_thermal = "60 - 70" - elif GPIO.input(17) == GPIO.HIGH and not GPIO.input(18) == GPIO.HIGH: - slave_fanmode = 50 - slave_thermal = "40 - 60" - elif not GPIO.input(17) == GPIO.HIGH and GPIO.input(18) == GPIO.HIGH: - slave_fanmode = 25 - slave_thermal = "0 - 40" - elif not GPIO.input(17) == GPIO.HIGH and not GPIO.input(18) == GPIO.HIGH: - slave_fanmode = 100 - slave_thermal = "70 - 100" - else: - slave_fanmode = 100 - slave_thermal = "-" - - # get other system infos and Minecraft Server stats - cpu_usage, cpu_freq, cpu_up, total_ram, ram_usage, ram_free, ram_percent, swap_percent, disk_percent = sys_monitor(cpu_usage, cpu_freq, cpu_up, total_ram, ram_usage, ram_free, ram_percent, swap_percent, disk_percent) - mc_motd, mc_version, mc_players_max, mc_players_on, mc_version_brand, mc_plugins, mc_player_list = mcserver(mc_motd, mc_version, mc_players_max, mc_players_on, mc_version_brand, mc_plugins, mc_player_list) - - # determine the PI with higher CPU temperature - if ignore_slave: - fanspeed = fanmode - else: - if slave_fanmode > fanmode: - fanspeed = slave_fanmode - else: - fanspeed = fanmode - - if fanmode < 50: - fanspeed2 = 0 - GPIO.output(25, False) - elif fanmode >= 50: - fanspeed2 = 100 - GPIO.output(25, True) - elif thermal >= 85: - os.system("sudo poweroff") - - i = 0 - - - if fanmode == 100: - GPIO.output(4, True) - time.sleep(2) - elif fanmode == 75: - while i < 6: - GPIO.output(4, True) - time.sleep(0.3) - GPIO.output(4, False) - time.sleep(0.1) - i = i + 1 - elif fanmode == 50: - while i < 6: - GPIO.output(4, True) - time.sleep(0.2) - GPIO.output(4, False) - time.sleep(0.2) - i = i + 1 - elif fanmode == 25: - while i < 6: - GPIO.output(4, True) - time.sleep(0.1) - GPIO.output(4, False) - time.sleep(0.3) - i = i + 1 - else: - GPIO.output(4, True) - time.sleep(2) - - # write all data to list - system_infos = [fanmode, slave_fanmode, fanspeed, fanspeed2, thermal, slave_thermal, cpu_usage, cpu_freq, cpu_up, total_ram, ram_usage, ram_free, ram_percent, swap_percent, disk_percent, mc_motd, mc_version, mc_players_max, mc_players_on, mc_version_brand, mc_plugins, mc_player_list] - - # delete all text in file and write list to file - file = open(file_path, 'r+') - file.truncate(0) - file.close() - file = open(file_path, 'w') - for e in system_infos: - file.write(str(e)) - file.write(";") - file.close() - - stop_time = time.time() - - if print_stats: - print("---------- Uptime: " + str(cpu_up) + " ----------") - print("Loop time:\t" + str(round(stop_time - start_time, 2)) + "\ts") - print("CMD Uptime:\t" + str(round(stop_time - launch_time, 2)) + "\ts") - print("CPU") - print("\tusage:\t" + str(cpu_usage) + "\t%") - print("\tfreq:\t" + str(cpu_freq) + "\tMHz") - print("\ttemp:\t" + str(thermal) + "\tC") - print("RAM") - print("\tusage:\t" + str(ram_percent) + "\t%") - print("\tswap :\t" + str(swap_percent) + "\t%") - print("Disks") - print("\tusage:\t" + str(disk_percent) + "\t%") - print("FANMODE") - print("\tmain:\t" + str(fanmode) + "\t%") - print("\tslave:\t" + str(slave_fanmode) + "\t%") - print("\tglobal:\t" + str(fanspeed) + "\t%") - print("\t2ndary:\t" + str(fanspeed2) + "\t%") - \ No newline at end of file +# - bundle all infos together for Network fetches +# - manage Fan speeds based on fan curve and cpu temps of both pi's +# - binary task feedback LED with button on front IO \ No newline at end of file diff --git a/pi-slave/main.py b/pi-slave/main.py index 0532fed..1d79705 100644 --- a/pi-slave/main.py +++ b/pi-slave/main.py @@ -1,57 +1,29 @@ -import RPi.GPIO as GPIO -import subprocess -import time +# Purpose +# - transmit the following to RPI4 using binary: +# - CPU temps (low <30°; medium 30°60°) -# GPIO setup -GPIO.setmode(GPIO.BCM) -GPIO.setwarnings(False) +# - receive the following from Arduino using binary: +# - used current of RPI 4 +# - used current of RPI 1.2 +# - uptime +# - cpu usage (core #0 - #3) +# - cpu frequency +# - cpu temps (RPI 4) +# - ram usage +# - am capacity +# - swap usuage +# - disk usage +# - disk capacity +# - disk used +# - mc server motd +# - mc sever version +# - mc server version brand +# - mc server players max +# - mc server players online +# - mc server plugins +# - mc server player_list +# - amount of connected devices +# - fan speed 180mm fan +# - fan speed 40mm fan -# Powering Status Pin to indicate that control program is up -GPIO.setup(4, GPIO.OUT) -GPIO.output(4, True) - -# setting up communication pins for binary fanmode transmission -GPIO.setup(17, GPIO.OUT) -GPIO.setup(18, GPIO.OUT) - -# define default variables -> fan speed will be at max. if someting goes wrong with getting cpu temps -thermal = -99 -fanmode = 100 -i = 0 - -# function to get cpu temperature on linux and macOS and decide on fan speed. -def temp(thermal, fanmode): - thermal = int(round(float(subprocess.check_output("cat /sys/class/thermal/thermal_zone0/temp", shell=True).rstrip())/1000,2)) - if thermal <= 20: - fanmode = 0 - elif 20 < thermal <= 40: - fanmode = 25 - elif 40 < thermal <= 60: - fanmode = 50 - elif 60 < fanmode <= 70: - fanmode = 75 - elif 70 < fanmode: - fanmode = 100 - return thermal, fanmode - -# main loop -while True: - # get cpu temp - thermal, fanmode = temp(thermal, fanmode) - if fanmode == 0 or fanmode == 25: - GPIO.output(17, False) - GPIO.output(18, True) - elif fanmode == 50: - GPIO.output(17, True) - GPIO.output(18, False) - elif fanmode == 75: - GPIO.output(17, True) - GPIO.output(18, True) - else: - GPIO.output(17, False) - GPIO.output(18, False) - # cpu temp will be updated every 5 seconds - time.sleep(5) - i += 1 - # log cpu temp and fan speed - print("----- Run Nr.:", i, "\nCpu temperature measured: ", str(thermal) + "°C", "- Fanspeed: ", str(fanmode) + "%") \ No newline at end of file +# - Display the above listed stats using small display with buttons for modes \ No newline at end of file