Skip to content

Instantly share code, notes, and snippets.

@stevennic22
Last active June 6, 2020 04:09
Show Gist options
  • Save stevennic22/2cd69cbb86bbdff38413c3633a7141c2 to your computer and use it in GitHub Desktop.
Save stevennic22/2cd69cbb86bbdff38413c3633a7141c2 to your computer and use it in GitHub Desktop.
Updated Folding@Home Telnet monitoring script
Sun May 17 05:20:08 2020
StevensPC: 215k ppd
Slot: 01 - Unit: 02: DOWNLOAD, 0 attempts
Slot: 00 - Unit: 03: RUNNING, 41.23% done, ETA: 02:25:00, Points: 23466
Slot: 01_01 - Unit: 01: RUNNING, 99.51% done, ETA: 00:01:55, Points: 131020
Slot: 02 - Unit: 00: RUNNING, 53.54% done, ETA: 05:53:00, Points: 60611
FoldingServer: 27k ppd
Slot: 00 - Unit: 01: RUNNING, 82.70% done, ETA: 00:33:09, Points: 26954
HPFolding: 5902 ppd
Slot: 00 - Unit: 00: RUNNING, 2.23% done, ETA: 08:47:00, Points: 5902
Total ppd= 248k ppd
#!/usr/bin/env python3
## Original script source: https://forums.anandtech.com/threads/folding-home-fahclient-config-control-manual-page.2574018/#post-40108202
import time, sys, telnetlib
# Enter one or more hosts here.
# Can be 'localhost', or IP addresses like '192.168.0.5', or hostnames.
# Enclose in '' and separate by comma.
hosts = [
#['IP or hostname', port , "DisplayName in output"],
['StevensPC.home', 36330 , "StevensPC"],
['10.10.10.250', 36330, "FoldingServer"],
['10.10.10.242', 36330, "HPFolding"]
]
# The intervals in which to check, in minutes:
loopdelay = 5
# Enable/Disable continuous looping
loop = True
# Enable debug output
debug = False
def format_ppd(ppd):
if ppd >= 1e6:
return "%.2fM ppd" % (ppd / 1e6)
if ppd >= 1e4:
return "%.0fk ppd" % (ppd / 1e3)
return "%d ppd" % (ppd)
def format_duration(dur):
d = dur // (24*3600)
dur -= d*24*3600
h = dur // 3600
dur -= h*3600
m = dur // 60
dur -= m*60
s = dur
if d > 0:
return "%02.0fd%02.0fh" % (d, h)
else:
return "%02.0f:%02.0f:%02.0f" % (h, m, s)
def parse_duration(dur):
d = 0.
for t in dur.split():
if t == 'days':
return d*24.*3600.
elif t == 'hours':
d *= 60.
elif t == 'mins':
d *= 60.
elif t == 'secs':
pass
else:
d += float(t)
return d
# Class to handle client information and connections
class FAHClients:
def __init__(self, name, ip, port):
self.name = name
self.ip = ip
self.port = port
self.host_ppd = 0
#Class function to gather queue information and handle connection to servers
def connect_to_server(self):
try:
x = 0
while x < 2:
self.tn = telnetlib.Telnet(self.ip, self.port, 10)
if debug:
print("\nConnecting...")
self.tn.set_debuglevel(100)
buftest = self.tn.read_until(b'Welcome to the FAHClient command server.\n> ', 10).decode('utf-8')
if "FAHClient" not in buftest:
self.tn.write(b'exit\n')
self.tn.close()
x += 1
continue
self.tn.write(b'slot-info\n')
slotbuf = self.tn.read_until(b'---\n', 10).decode('utf-8')
slots = eval(slotbuf.split('PyON 1 slots\n')[1].split('\n---\n')[0])
trip = True
for x in slots:
if x["status"] == "RUNNING":
trip = False
if trip:
self.queue = []
return("Information retrieved")
self.tn.write(b'queue-info\n')
bufdec = self.tn.read_until(b'---\n>', 10).decode('utf-8')
self.tn.write(b'exit\n')
self.tn.close()
if len(bufdec.split('PyON 1 units\n')) > 1:
self.queue = eval(bufdec.split('PyON 1 units\n')[1].split('\n---\n')[0])
if len(self.queue) > 0:
break
x += 1
else:
if not hasattr(self, "queue"):
raise(TimeoutError)
except TimeoutError as err:
return("Cannot retrieve info")
except:
if debug:
print(sys.exc_info())
return("Cannot connect")
return("Information Retrieved")
#Parses the information for each host
def parse_info(self):
self.slots = {}
for i in self.queue:
if debug:
print(i)
indx = i['slot']
x = 1
#Adjusts slot index to handle multiple instances of slots (when downloading and working at the same time).
while indx in self.slots:
if x < 10:
indx = i['slot'] + "_0" + str(x)
else:
indx = i['slot'] + "_" + str(x)
x += 1
self.slots[indx] = {"state": i['state'], "unit": i["id"], "waiting": i["waitingon"]}
#Store targeted information from queue based on state
if i['state'] == 'DOWNLOAD':
self.slots[indx]['attempts'] = i['attempts']
if self.slots[indx]['attempts'] > 0:
self.slots[indx]["download_duration"] = parse_duration(i['nextattempt'])
self.slots[indx]["formatted_duration"] = format_duration(self.slots[indx]["download_duration"])
else:
self.slots[indx]["download_duration"] = ""
self.slots[indx]["formatted_duration"] = ""
elif i['state'] == 'RUNNING':
self.host_ppd += int(i['ppd'])
self.slots[indx]["ppd"] = int(i['ppd'])
self.slots[indx]["pctdone"] = i['percentdone']
self.slots[indx]["duration"] = format_duration(parse_duration(i['eta']))
elif i['state'] == 'SEND':
self.slots[indx]["cs"] = i["cs"]
self.slots[indx]["ws"] = i["ws"]
self.slots[indx]["sunit"] = i["unit"]
def main():
print(time.ctime(), end="\n\n")
total_ppd = 0
for h in hosts:
if len(h) > 2:
host = FAHClients(h[2], h[0], h[1])
else:
host = FAHClients(h[0], h[0], h[1])
print(host.name, end="")
conn = host.connect_to_server()
#Skip parsing information if no information to parse.
if "cannot" in conn.lower():
print("\n" + conn, end="\n\n")
continue
host.parse_info()
total_ppd += host.host_ppd
print(': {0!s}'.format(format_ppd(host.host_ppd)))
#Loop through hosts and output queue info based on state
for slot, info in host.slots.items():
print("Slot: {slot!s} - Unit: {id!s}: {state!s}".format(slot=slot, id=info["unit"], state=info["state"]), end="")
if info["state"] == "DOWNLOAD":
if info['attempts'] > 0:
print(', {attempts!s} attempts, next in {duration}'.format(attempts=info['attempts'], duration=info['formatted_duration']))
else:
print(', 0 attempts')
elif info["state"] == "RUNNING":
print(", {pctdone} done, ETA: {eta}, Points: {ppd}".format(pctdone=info["pctdone"], eta=info["duration"], ppd = info["ppd"]))
elif info['state'] == 'SEND':
print(' ~{unit} to ws {ws}, cs {cs}'.format(unit=info["sunit"][-8:], ws=info["ws"], cs=info["cs"]))
elif info['state'] == 'READY':
if info["waiting"] == "":
print(", PAUSED")
else:
print(', waiting on: {0}'.format(info["waiting"]))
if host.slots.__len__() < 1:
print("No active work units")
print("")
if len(hosts) >= 1:
print('\nTotal ppd= {total}'.format(total=format_ppd(total_ppd)), end="\n\n")
if __name__ == "__main__":
main()
while loop:
time.sleep(loopdelay*60)
print("------------------------------------------", end="\n\n\n")
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment