diff --git a/README.md b/README.md index 01ad330..3b0a981 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Required for this to work without any modifications are: ### PC Module The PC module requests all kinds of system information from both Raspberry PI'S making use of FTP. The Raspberry PI hosts an FTP server from which the PC fetches the text file `output.txt` containing all infos. -### Rpi Master Module +### RPi Master Module The Rpi Master Module (or Raspberry Pi Master module) gets all sorts of informations from its own system and Minecraft Servers and writes them to the `output.txt` file. It also gets fanspeed requirments from the **RPi Slave Module** making use of binary signal transmission over 2 GPIO pins. This module then controls the fan speeds. ### RPi Slave Module diff --git a/pi-master/main.py b/pi-master/main.py new file mode 100644 index 0000000..d6859d1 --- /dev/null +++ b/pi-master/main.py @@ -0,0 +1,281 @@ +from http import server +import RPi.GPIO as GPIO +import subprocess, os, time, psutil + +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 v0.0.1 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(244, 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(24, True) + time.sleep(2) + elif fanmode == 75: + while i < 6: + GPIO.output(24, True) + time.sleep(0.3) + GPIO.output(24, False) + time.sleep(0.1) + i = i + 1 + elif fanmode == 50: + while i < 6: + GPIO.output(24, True) + time.sleep(0.2) + GPIO.output(24, False) + time.sleep(0.2) + i = i + 1 + elif fanmode == 25: + while i < 6: + GPIO.output(24, True) + time.sleep(0.1) + GPIO.output(24, False) + time.sleep(0.3) + i = i + 1 + else: + GPIO.output(24, 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 diff --git a/pi1/main.py b/pi-slave/main.py similarity index 84% rename from pi1/main.py rename to pi-slave/main.py index 94d7347..0532fed 100644 --- a/pi1/main.py +++ b/pi-slave/main.py @@ -1,57 +1,57 @@ -import RPi.GPIO as GPIO -import subprocess -import time - -# 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.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 = str(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 - 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: ", thermal + "°C", "- Fanspeed: ", fanmode + "%") \ No newline at end of file +import RPi.GPIO as GPIO +import subprocess +import time + +# 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.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 diff --git a/pi4/main.py b/pi4/main.py deleted file mode 100644 index 84e99b4..0000000 --- a/pi4/main.py +++ /dev/null @@ -1,165 +0,0 @@ -from http import server -import RPi.GPIO as GPIO -import subprocess, os, time - -# 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) -GPIO.setup(18, GPIO.IN) - -# setting up control pin for fancontrol -GPIO.setuo(4, 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 - -file = open("output.txt", 'r+') - -cpu_usage = "--" -total_ram = "--.--" -ram_usage = "--.--" -ram_free = "--.--" - -# 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 = str(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 - -# function to round values -def display(val): - return round(float(val),2) - -# function to get system informations -def sys_monitor(cpu_usage, total_ram, ram_usage, ram_free): - cpu_usage = str(round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline()),2)) - total_ram = str(round(display(subprocess.check_output("free | awk 'FNR == 2 {print $2/1000000}'", shell=True)))) - ram_usage = str(subprocess.check_output("free | awk 'FNR == 2 {print $3/($3+$4)*100}'", shell=True)) - ram_free = str(100 - display(ram_usage)) - return cpu_usage, total_ram, ram_usage, ram_free - -# 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) - status = mcserver.status() - mc_motd = status.description - mc_version = status.version.name - mc_players_max = status.players.max - mc_players_on = status.players.online - - # 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 - 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 - - # 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: - # eecute temperature function - - temp(thermal, fanmode) - # determine fanmode of 2nd raspberry PI and guess CPU temps - if GPIO.input(17) and GPIO.input(18): - slave_fanmode = 75 - slave_thermal = "60 - 70" - elif GPIO.input(17) and not GPIO.input(18): - slave_fanmode = 50 - slave_thermal = "40 - 60" - elif not GPIO.input(17) and GPIO.input(18): - slave_fanmode = 25 - slave_thermal = "0 - 40" - elif not GPIO.input(17) and not GPIO.input(18): - slave_fanmode = 100 - slave_thermal = "70 - 100" - else: - slave_fanmode = 100 - slave_thermal = "-" - - # get other system infos and Minecraft Server stats - sys_monitor(cpu_usage, total_ram, ram_usage, ram_free) - mcserver(mc_motd, mc_version, mc_players_max, mc_players_on, mc_version_brand, mc_plugins, mc_player_list) - - # write all data to list - system_infos = [fanmode, slave_fanmode, thermal, slave_thermal, cpu_usage, total_ram, ram_usage, ram_free, 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.truncate(0) - for e in system_infos: - file.write(e) - file.write(";") - - # determine the PI with higher CPU temperature - if slave_fanmode > fanmode: - fanspeed = slave_fanmode - else: - fanspeed = fanmode - if fanmode == 100: - GPIO.output(4, True) - time.sleep(5) - elif fanmode == 75: - while i < 12: - GPIO.output(4, True) - time.sleep(0.3) - GPIO.outut(4, False) - time.sleep(0.1) - i += 1 - elif fanmode == 50: - while i < 25: - GPIO.output(4, True) - time.sleep(0.1) - GPIO.output(4, False) - time.sleep(0.1) - i += 1 - elif fanmode == 25: - while i < 12: - GPIO.output(4, True) - time.sleep(0.1) - GPIO.outut(4, False) - time.sleep(0.3) - i += 1 - else: - GPIO.output(4, True) - time.sleep(5) \ No newline at end of file diff --git a/src/circuit.png b/src/circuit.png index 9fbe70e..09dff32 100644 Binary files a/src/circuit.png and b/src/circuit.png differ