It works!
This commit is contained in:
		
							
								
								
									
										162
									
								
								zpool-switch.py
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								zpool-switch.py
									
									
									
									
									
								
							| @@ -1,33 +1,25 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| # API description: http://www.zpool.ca/site/api | ||||
| # estimates: values in mBTC/MH/day,  | ||||
| #                      mBTC/PH/day for sha256 | ||||
| #		       mBTC/GH/day for scrypt, blake, decred, x11, quark, qubit | ||||
| #		       mBTC/kS/day for equihash | ||||
| # API description (such as it is): http://www.zpool.ca/site/api | ||||
|  | ||||
| import pprint | ||||
| import json | ||||
| import urllib.request | ||||
| import urllib.parse | ||||
| import sys | ||||
| import datetime | ||||
| import time | ||||
| import subprocess | ||||
| import os | ||||
| import socket | ||||
| import urllib.request | ||||
| import urllib.parse | ||||
|  | ||||
| # load config | ||||
|  | ||||
| DEBUG=False | ||||
|  | ||||
| cfg=json.loads(open(sys.argv[1]).read()) | ||||
| miners=json.loads(open(sys.argv[2]).read()) | ||||
| algo_map=json.loads(open(sys.argv[3]).read()) | ||||
|  | ||||
| card_type=cfg["card_type"] | ||||
| #user_name=cfg["user_name"] | ||||
| #miner_name=cfg["miner_name"] | ||||
| currency=cfg["currency"] | ||||
| pwrcost=cfg["pwrcost"] | ||||
| min_profit=cfg["min_profit"] | ||||
| @@ -36,29 +28,20 @@ payment_addr=cfg["payment_addr"] | ||||
|  | ||||
| os.environ["DISPLAY"]=":0" | ||||
|  | ||||
| # IPv4 address lookup | ||||
|  | ||||
| def addr(host): | ||||
|   return [addr[4][0] for addr in socket.getaddrinfo(host, None) if addr[0] == socket.AF_INET][0] | ||||
|  | ||||
| # grab something from a website | ||||
|  | ||||
| def fetch(prot, host, path, forceipv4=False): | ||||
|   if (forceipv4): | ||||
|     url=prot+"://"+addr(host)+"/"+path | ||||
|   else: | ||||
|     url=prot+"://"+host+"/"+path | ||||
|   r=urllib.request.Request(url, None, {"User-Agent": "Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1", "Pragma": "no-cache", "Host": host}) | ||||
| def fetch(url): | ||||
|   r=urllib.request.Request(url, None, {"User-Agent": "Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1", "Pragma": "no-cache"}) | ||||
|   return urllib.request.urlopen(r).read().decode("utf-8") | ||||
|  | ||||
| # main | ||||
|  | ||||
| if (DEBUG!=True): | ||||
|   exchrate=float(json.loads(fetch("https", "api.coinbase.com", "/v2/exchange-rates?currency=BTC"))["data"]["rates"][currency]) | ||||
|   data=json.loads(fetch("http", "www.zpool.ca", "/api/status", True)) | ||||
| else: | ||||
|   exchrate=float(json.loads(open("dbgdata-exchange-rates").read())["data"]["rates"][currency]) | ||||
|   data=json.loads(open("dbgdata-status").read()) | ||||
| try: | ||||
|   exchrate=float(json.loads(fetch("https://api.coinbase.com/v2/exchange-rates?currency=BTC"))["data"]["rates"][currency]) | ||||
|   data=json.loads(fetch("http://www.zpool.ca/api/status")) | ||||
| except: | ||||
|   print("unable to retrieve remote data", file=sys.stderr) | ||||
|   sys.exit(-1) | ||||
|  | ||||
| # update algo map | ||||
|  | ||||
| @@ -74,23 +57,36 @@ if (changed==True): | ||||
|   with open(sys.argv[3], "w") as outfile: | ||||
|     json.dump(algo_map, outfile, sort_keys=True, indent=2) | ||||
|  | ||||
| # adjust estimates so they're all in the same units: BTC/day per GH/s  | ||||
| # weed out miners not supported by the pool | ||||
|  | ||||
| filtered_miners={} | ||||
| for i in data: | ||||
|   data[i]["adjusted_estimate"]=float(data[i]["estimate_current"])*1000 | ||||
|   try: | ||||
|     filtered_miners[algo_map[i]]=miners[algo_map[i]] | ||||
|   except: | ||||
|     pass | ||||
| miners=filtered_miners | ||||
|  | ||||
| # adjust estimates so they're all in the same units: BTC/day per GH/s  | ||||
|  | ||||
| for i in data: | ||||
|   data[i]["estimate_current"]=float(data[i]["estimate_current"])*1000 | ||||
| try: | ||||
|   data["sha256"]["adjusted_estimate"]/=1000000000000 | ||||
|   data["sha256"]["estimate_current"]/=1000000000 | ||||
| except: | ||||
|   pass | ||||
| try: | ||||
|   data["equihash"]["adjusted_estimate"]*=1000 | ||||
|   data["equihash"]["estimate_current"]*=1000 | ||||
| except: | ||||
|   pass | ||||
| for i in ["scrypt", "blakecoin", "blake2s", "decred", "x11", "quark", "qubit", "keccak"]: | ||||
|   try: | ||||
|     data[i]["adjusted_estimate"]/=1000 | ||||
|     data[i]["estimate_current"]/=1000 | ||||
|   except: | ||||
|     pass | ||||
|  | ||||
| # calculate profitability for our hardware | ||||
|  | ||||
| coins={} | ||||
| for i in data: | ||||
|   if (algo_map[i]!=""): | ||||
| @@ -99,13 +95,99 @@ for i in data: | ||||
|     coins[i]["algo"]=i | ||||
|     coins[i]["mapped_algo"]=algo_map[i] | ||||
|     coins[i]["name"]=i | ||||
|     coins[i]["estimate"]=data[i]["adjusted_estimate"]*float(coins[i]["speed"]) # factor in our speed     | ||||
|      | ||||
| for i in data: | ||||
|   print(i+": "+str(data[i]["estimate_current"])+" "+str(data[i]["adjusted_estimate"])) | ||||
|    | ||||
| print("") | ||||
|     coins[i]["estimate"]=data[i]["estimate_current"]*float(coins[i]["speed"])-24.0*coins[i]["power"]*pwrcost/exchrate | ||||
|  | ||||
| # sort by profitability | ||||
|  | ||||
| sort={} | ||||
| for i in coins: | ||||
|   print(i+": "+str(coins[i]["estimate"])) | ||||
|   sort[i]=coins[i]["estimate"] | ||||
| sort=sorted(sort.items(), key=lambda x:x[1], reverse=True) | ||||
|  | ||||
| log=open("current-profit", "w") | ||||
| for i in sort: | ||||
|   log.write(i[0]+": "+format(i[1], ".8f")+" BTC/day ("+format(i[1]*exchrate, ".2f")+" "+currency+"/day)\n") | ||||
| log.close() | ||||
|  | ||||
| miner=coins[sort[0][0]] | ||||
|  | ||||
| if (len(sys.argv)==4): | ||||
|   # exit if maximum is below minimum | ||||
|   if (miner["estimate"]<min_profit): | ||||
|     algo_log=open("algo-log", "a") | ||||
|     algo_log.write(str(datetime.datetime.now())+": **NONE**\n") | ||||
|     algo_log.close() | ||||
|     for algo in coins: | ||||
|       subprocess.call(["pkill", "-f", "^"+coins[algo].replace("+", "\\+")]) | ||||
|     sys.exit() | ||||
| else: # manual override | ||||
|   if (sys.argv[4]!="list"): | ||||
|     miner=coins[sys.argv[4]] | ||||
|   else: # list available algos | ||||
|     print("algos: ", end="") | ||||
|     for i in coins: | ||||
|       print(i+" ", end="") | ||||
|     print("") | ||||
|     sys.exit() | ||||
|  | ||||
| # see if miner's already running | ||||
| try: | ||||
|   subprocess.check_output(["pgrep", "-f", "^"+miner["bin"].replace("+", "\\+")]) | ||||
|   current=True | ||||
| except: | ||||
|   current=False | ||||
| other=False; | ||||
| if (current==False): | ||||
|   for algo in miners: | ||||
|     try: | ||||
|       subprocess.check_output(["pgrep", "-f", "^"+miners[algo]["bin"].replace("+", "\\+")]) | ||||
|       other=True | ||||
|     except: | ||||
|       pass | ||||
|  | ||||
| if (current==False): | ||||
|   # log a change | ||||
|   algo_log=open("algo-log", "a") | ||||
|   algo_log.write(str(datetime.datetime.now())+": * ("+miner["algo"]+") "+format(miner["estimate"], ".8f")+" "+format(miner["estimate"]*exchrate, ".2f")+"\n") | ||||
|   algo_log.close() | ||||
|   # kill existing miners | ||||
|   for algo in miners: | ||||
|     subprocess.call(["pkill", "-f", "^"+miners[algo]["bin"].replace("+", "\\+")]) | ||||
|   time.sleep(3) | ||||
|   if (card_type=="nvidia"): # update card settings | ||||
|     cards=int(subprocess.check_output("nvidia-smi --query-gpu=count --format=csv,noheader,nounits".split(" ")).decode("utf-8").split("\n")[-2]) | ||||
|     for i in range(0, cards): | ||||
|       # power limit | ||||
|       if type(miner["power_limit"]) is int: | ||||
|         subprocess.call(("sudo nvidia-smi -i "+str(i)+" -pl "+str(miner["power_limit"])).split(" ")) | ||||
|       else: | ||||
|         subprocess.call(("sudo nvidia-smi -i "+str(i)+" -pl "+str(miner["power_limit"][i])).split(" ")) | ||||
|       # core overclock | ||||
|       if type(miner["gpu_oc"]) is int: | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[2]="+str(miner["gpu_oc"])).split(" ")) | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[3]="+str(miner["gpu_oc"])).split(" ")) | ||||
|       else: | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[2]="+str(miner["gpu_oc"][i])).split(" ")) | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[3]="+str(miner["gpu_oc"][i])).split(" ")) | ||||
|       # memory overclock | ||||
|       if type(miner["mem_oc"]) is int: | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[2]="+str(miner["mem_oc"])).split(" ")) | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[3]="+str(miner["mem_oc"])).split(" ")) | ||||
|       else: | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[2]="+str(miner["mem_oc"][i])).split(" ")) | ||||
|         subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[3]="+str(miner["mem_oc"][i])).split(" ")) | ||||
|       # fan speed | ||||
|       if type(miner["fan"]) is int: | ||||
|         if (miner["fan"]==0): | ||||
|           subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=0").split(" ")) | ||||
|         else: | ||||
|           subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=1").split(" ")) | ||||
|           subprocess.call(("nvidia-settings -a [fan:"+str(i)+"]/GPUTargetFanSpeed="+str(miner["fan"])).split(" ")) | ||||
|       else: | ||||
|         if (miner["fan"][i]==0): | ||||
|           subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=0").split(" ")) | ||||
|         else: | ||||
|           subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=1").split(" ")) | ||||
|           subprocess.call(("nvidia-settings -a [fan:"+str(i)+"]/GPUTargetFanSpeed="+str(miner["fan"][i])).split(" ")) | ||||
|   # launch new miner | ||||
|   subprocess.call(("screen -dmS miner "+miner["bin"]).split(" ")) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user