def initStats(self): """Query and parse cgminer device api call.""" self._statusDict = {} for port in self._ports: cgminer = CgminerAPI(self._host, int(port)) self._statusDict[port] = cgminer.command('devs', None)['DEVS']
def __init__(self): # Define supported algo self.algos = {} self.profitability_log = None self.__load_config() self.api = TradeMyBitAPI(self.api_key, 'https://pool.trademybit.com/api/') self.cgminer = CgminerAPI(self.cgminer_host, self.cgminer_port) # We track state in a variable self.current_algo = None
def FindActivePool(miner): a=CgminerAPI(miner["hostname"], miner["rpc_port"]) pools=a.pools()["POOLS"] for i in range(0, len(pools)): try: if (pools[i]["Stratum Active"]==True): return pools[i]["Stratum URL"] except: pass # TODO: add checks for non-stratum servers return ""
def CheckMiners(miners, accepted, rejected): rtnval={} for i, miner in enumerate(miners): try: a=CgminerAPI(miners[miner]["hostname"], miners[miner]["rpc_port"]) summary=a.summary()["SUMMARY"] if (accepted[miner]==summary[0]["Accepted"] and rejected[miner]==summary[0]["Rejected"] and accepted[miner]!=-1 and rejected[miner]!=-1): rtnval[miner]=FindActivePool(miners[miner]) accepted[miner]=summary[0]["Accepted"] rejected[miner]=summary[0]["Rejected"] except: pass return rtnval
def SwitchPool(hostname, port, pool_url, pool_worker, pool_passwd, clear=1): a=CgminerAPI(hostname, port) # add pool a.addpool(pool_url+","+pool_worker+","+pool_passwd) time.sleep(1) # wait for the connection live=0 while (live==0): for i, pool in enumerate(a.pools()["POOLS"]): if (pool["URL"]==pool_url and pool["User"]==pool_worker): live=1 if (live==0): time.sleep(1) # switch to new pool and find it pools=a.pools()["POOLS"] delete_list=[] found=0 for i, pool in enumerate(pools): if (pool["URL"]==pool_url and pool["User"]==pool_worker and found==0): found=1 a.switchpool(pool["POOL"]) else: delete_list.append(pool["POOL"]) # remove other pool entries if (clear==1): delete_list.sort(reverse=True) for i, num in enumerate(delete_list): a.removepool(num)
def __init__(self): self.api = CgminerAPI() self.config_path = os.path.dirname(os.path.realpath(__file__)) + '/config/cgminer'
class Cgminer: def __init__(self): self.api = CgminerAPI() self.config_path = os.path.dirname(os.path.realpath(__file__)) + '/config/cgminer' def active(self): output = os.popen('ps x | grep cgminer').read() if re.search('config/cgminer', output): return True return False def start(self): subprocess.Popen(['cgminer', '-c', 'config/cgminer', '-T'], stdout=open('logs', 'w')) def stop(self): subprocess.Popen(['killall', 'cgminer'], stdout=subprocess.PIPE) def restart(self): self.stop() time.sleep(3) self.start() def devices(self): data = {} try: data['edevs'] = self.api.edevs() except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) try: data['estats'] = self.api.estats() except Exception as e: raise CgminerError('Problem with API estats method: ' + e.message) result = [] try: for i in xrange(0, len(data['edevs']['DEVS'])): dev = data['edevs']['DEVS'][i] stat = data['estats']['STATS'][i] result.append({ 'id': dev['ID'], 'name': dev['Name'], 'mhs': dev['MHS 1m'], 'ghs': dev['MHS 1m'] / 1000, 'temperature': dev['Temperature'], 'accepted': dev['Accepted'], 'rejected': dev['Rejected'], 'clockrate': stat['base clockrate'], 'fan': stat['fan percent'], 'voltage': stat['Asic0 voltage 0'] }) except Exception as e: raise CgminerError('Problem with devices data preparing: ' + e.message) return result def summary(self): try: summary = self.api.summary() except Exception as e: raise CgminerError('Problem with API summary method: ' + e.message) try: pools = self.api.pools() except Exception as e: raise CgminerError('Problem with API pools method: ' + e.message) try: edevs = self.api.edevs() except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) try: total = summary['SUMMARY'][0]['Accepted'] + summary['SUMMARY'][0]['Rejected'] if total == 0: accepted_percent = 0 rejected_percent = 0 else: accepted_percent = int(summary['SUMMARY'][0]['Accepted'] / total * 100) rejected_percent = int(summary['SUMMARY'][0]['Rejected'] / total * 100) result = { 'mhs': 0, 'ghs': 0, 'accepted': summary['SUMMARY'][0]['Accepted'], 'rejected': summary['SUMMARY'][0]['Rejected'], 'accepted_percent': accepted_percent, 'rejected_percent': rejected_percent, 'pool': { 'url': pools['POOLS'][0]['URL'], 'user': pools['POOLS'][0]['User'] } } for edev in edevs['DEVS']: result['mhs'] += edev['MHS 1m'] result['ghs'] += edev['MHS 1m'] / 1000 except Exception as e: raise CgminerError('Problem with summary data preparing: ' + e.message) return result def pools(self): with open(self.config_path, 'r') as f: return json.loads(f.read())['pools'] # TODO: catch exceptions def update_pools(self, pools): ordered_pools = sorted(pools, key=lambda pool: int(pool['priority'])) with open(self.config_path, 'r') as f: config = json.loads(f.read()) config['pools'] = ordered_pools with open(self.config_path, 'w') as f: json.dump(config, f) def clockrate(self): with open(self.config_path, 'r') as f: return json.loads(f.read())['hfa-hash-clock'] def update_clockrate(self, clockrate): with open(self.config_path, 'r') as f: config = json.loads(f.read()) config['hfa-hash-clock'] = clockrate with open(self.config_path, 'w') as f: json.dump(config, f) def fan_speed(self): with open(self.config_path, 'r') as f: config = json.loads(f.read()) if 'hfa-fan' in config: return config['hfa-fan'] else: return 'auto' def update_fan_speed(self, fan_speed): with open(self.config_path, 'r') as f: config = json.loads(f.read()) if fan_speed == 'auto': if 'hfa-fan' in config: del config['hfa-fan'] else: config['hfa-fan'] = fan_speed with open(self.config_path, 'w') as f: json.dump(config, f) def overheat(self): with open(self.config_path, 'r') as f: return json.loads(f.read())['hfa-temp-overheat'] def update_overheat(self, overheat): with open(self.config_path, 'r') as f: config = json.loads(f.read()) config['hfa-temp-overheat'] = overheat with open(self.config_path, 'w') as f: json.dump(config, f) def save(self): try: print self.api.save(self.config_path) except Exception as e: raise CgminerError('Problem with API save method: ' + e.message) return True def latest_hashrate_poins(self): points = [] try: for edev in self.api.edevs()['DEVS']: points.append(edev['MHS 5m'] / 1000) except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) return points
class TradeMyBitSwitcher(object): def __init__(self): # Define supported algo self.algos = {} self.algos['scrypt'] = Algo('Scrypt') self.algos['nscrypt'] = Algo('N-Scrypt') self.profitability_log = None self.__load_config() self.api = TradeMyBitAPI(self.api_key, 'https://pool.trademybit.com/api/') self.cgminer = CgminerAPI(self.cgminer_host, self.cgminer_port) # We track state in a variable self.current_algo = None def main(self): try: # cnt_all = 0 # main loop print '-' * 72 while True: # print header # self.logger.info("<<< Round %d >>>" % (cnt_all+1)) # get data from sources self.logger.debug("Fetching data...") bestalgo = self.best_algo() self.logger.debug("=> Best: %s | Currently mining: %s" % (bestalgo, self.current_algo)) if bestalgo != self.current_algo and bestalgo != None: # i.e. if we're not already mining the best algo self.switch_algo(bestalgo) elif self.current_algo == None: # No miner running and profitability is similar, run the first algo self.logger.warning('No miner running') self.switch_algo(self.algos.keys()[0]) # sleep self.logger.debug('Going to sleep for %dmin...' % self.idletime) i = 0 while i < self.idletime*60: time.sleep(1) i += 1 except KeyboardInterrupt: self.logger.warn('Caught KeyboardInterrupt, terminating...') self.cleanup() def cleanup(self): """Cleanup our mess""" if self.profitability_log: self.profitability_file.close() sys.exit() def best_algo(self): """Retrieves the "bestalgo" from TMB api""" try: data = self.api.bestalgo() # parse json data into variables algo1 = data[0]["algo"] score1 = float(data[0]["score"]) algo2 = data[1]["algo"] score2 = float(data[1]["score"]) self.logger.debug("%s : %f | %s: %f" % (algo1, score1, algo2, score2)) # return result if (score2 - score1) / score1 > self.profitability_threshold: best = algo2 elif (score1 - score2) / score2 > self.profitability_threshold: best = algo1 else: best = None if self.profitability_log: self.profitability_log.writerow({'date': datetime.datetime.now(), algo1: score1, algo2: score2}) self.profitability_file.flush() return best except (socket.error, KeyError): self.logger.warning('Cannot connect to TMB API...') return None # # Return scrypt/nscrypt based on the version of the miner running # # Temporarly disabled to support sgminer since we can't reliably determine # # if sgminer is mining nfactor 10 or 11 # def current_algo(self): # try: # data = self.cgminer.version() # version = data['STATUS'][0]['Description'] # if version.startswith('vertminer'): # vertminer 0.5.4pre1 # return 'nscrypt' # elif version.startswith('cgminer'): # cgminer 3.7.2 # return 'scrypt' # else: # return None # except: # self.logger.warning('Cannot connect to miner API...') # return None def switch_algo(self, algo): """Tells the current miner to exit and start the other one""" self.logger.info('=> Switching to %s (running %s)' % (algo, self.algos[algo].command)) self.current_algo = algo try: self.cgminer.quit() time.sleep(self.switchtime) # Wait for it to quit / Or check the process id? except socket.error: pass # Cgminer not running try: subprocess.Popen(self.algos[algo].command) except OSError: self.logger.critical('Cannot execute [%s]!' % self.algos[algo].command) self.logger.critical('Make sure your miner startup scripts are executable before continuing.') sys.exit() def __prepare_logger(self, logging_config={}): """Configure the logger""" logfile = logging_config.get('logfile') # Set console log level based on the config if bool(logging_config.get('verbose')): log_level = logging.DEBUG else: log_level = logging.INFO # Prepare logger self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) ## Console logging # create console handler stream_handler = logging.StreamHandler() stream_handler.setLevel(log_level) # create formatter and add it to the handler formatter = logging.Formatter('%(asctime)s :: %(message)s', "%Y-%m-%d %H:%M:%S") stream_handler.setFormatter(formatter) # add the handler to the logger self.logger.addHandler(stream_handler) ## File logging if logfile: print "Logging to %s" % logfile # create file handler file_handler = logging.FileHandler(logfile, 'a') file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s :: %(levelname)8s :: %(message)s', "%Y-%m-%d %H:%M:%S") file_handler.setFormatter(formatter) self.logger.addHandler(file_handler) csv_file = logging_config.get('profitability_log') if csv_file: self.__prepare_profitability_log(csv_file) def __prepare_profitability_log(self, csv_file): # Check if file is already present to know if we need to write the headers write_header = not(os.path.isfile(csv_file)) self.profitability_file = open(csv_file, 'ab') self.profitability_log = csv.DictWriter(self.profitability_file, ['date', 'scrypt', 'nscrypt']) if write_header: self.profitability_log.writeheader() def __load_config(self): config_file = 'tmb-switcher.conf' # Check if the config file is present if not(os.path.isfile(config_file)): print "ERROR: Configuration file not found!" print "Make sure the tmb-switcher.conf file is present!" sys.exit() # Load the config file config = ConfigParser.ConfigParser() config.read(config_file) # Read the logging settings and setup the logger logging_config = dict(config.items('Logging')) self.__prepare_logger(logging_config) # Read the settings or use default values try: self.api_key = config.get('TradeMyBit', 'apikey') except: self.logger.critical("Could not read apikey from config file") sys.exit() try: self.idletime = config.getint('Misc','idletime') except: self.logger.warning("Could not read idletime from config file. Defaulting to 5 min") self.idletime = 5 try: self.switchtime = config.getint('Misc', 'switchtime') except: self.logger.warning("Could not read switchtime from config file. Defaulting to 1s") self.switchtime = 1 try: self.profitability_threshold = config.getfloat('Misc','profitability_threshold') except: self.logger.warning("Could not read profitability_threshold from config file. Defaulting to 10%") self.profitability_threshold = 0.1 try: self.cgminer_host = config.get('cgminer', 'host') except: self.logger.warning("Could not read cgminer host from config file. Defaulting to 127.0.0.1") self.cgminer_host = '127.0.0.1' try: self.cgminer_port = config.getint('cgminer', 'port') except: self.logger.warning("Could not read cgminer port from config file. Defaulting to 4028") self.cgminer_host = 4028 for key in self.algos: try: script = config.get('Scripts', key) if os.path.isfile(script): self.algos[key].command = script else: self.logger.critical('Script for %s not found!' % key) self.cleanup() except ConfigParser.NoOptionError : self.logger.warning('Script for %s not configured!' % key) continue
import os import json from time import sleep import paho.mqtt.client as mqtt from pycgminer import CgminerAPI cgminer = CgminerAPI(host=os.getenv('CGMINER_HOST'), port=int(os.getenv('CGMINER_PORT'))) def on_connect(client, userdata, flags, rc): if rc == 0: print("Connected to broker " + os.getenv('MQTT_HOST') + ":" + os.getenv('MQTT_PORT')) global Connected # Use global variable Connected = True # Signal connection else: print("Connection failed") client = mqtt.Client() # Register connect callback client.on_connect = on_connect # Set access token client.username_pw_set(os.getenv('MQTT_PASS')) # Connect to ThingsBoard using default MQTT port and 60 seconds keepalive interval client.connect(os.getenv('MQTT_HOST'), int(os.getenv('MQTT_PORT')), 60) client.loop_start() # start the loop
from pycgminer import CgminerAPI cgminer = CgminerAPI() summary = cgminer.summary() my_gpu0 = cgminer.gpu(0) my_gpu1 = cgminer.gpu(1) print my_gpu0
from datetime import datetime import requests from pycgminer import CgminerAPI from flask import Flask, jsonify from flask.ext.cache import Cache from flask_yeoman import flask_yeoman cgminer = CgminerAPI() app = Flask(__name__, static_folder='app') cache = Cache(app, config={'CACHE_TYPE': 'filesystem', 'CACHE_DIR': '/tmp/'}) app.config.update(DEBUG=False) app.config.from_pyfile('settings.cfg') app.register_blueprint(flask_yeoman) def _get_profile(): """ Retrieve profile data from Slush's Pool API. """ r = requests.get( 'https://mining.bitcoin.cz/accounts/profile/json/{0}'.format( app.config['SLUSH_TOKEN']), verify=False) r.raise_for_status() profile = r.json() profile['total_reward'] = str( float(profile['confirmed_reward']) + float(profile['unconfirmed_reward']))
class TradeMyBitSwitcher(object): def __init__(self): # Define supported algo self.algos = {} self.algos['scrypt'] = Algo('Scrypt') self.algos['nscrypt'] = Algo('N-Scrypt') self.profitability_log = None self.__load_config() self.api = TradeMyBitAPI(self.api_key, 'https://pool.trademybit.com/api/') self.cgminer = CgminerAPI(self.cgminer_host, self.cgminer_port) # We track state in a variable self.current_algo = None def main(self): try: # cnt_all = 0 # main loop print '-' * 72 while True: # print header # self.logger.info("<<< Round %d >>>" % (cnt_all+1)) # get data from sources self.logger.debug("Fetching data...") bestalgo = self.best_algo() self.logger.debug("=> Best: %s | Currently mining: %s" % (bestalgo, self.current_algo)) if bestalgo != self.current_algo and bestalgo != None: # i.e. if we're not already mining the best algo self.switch_algo(bestalgo) elif self.current_algo == None: # No miner running and profitability is similar, run the first algo self.logger.warning('No miner running') self.switch_algo(self.algos.keys()[0]) # sleep self.logger.debug('Going to sleep for %dmin...' % self.idletime) i = 0 while i < self.idletime * 60: time.sleep(1) i += 1 except KeyboardInterrupt: self.logger.warn('Caught KeyboardInterrupt, terminating...') self.cleanup() def cleanup(self): """Cleanup our mess""" if self.profitability_log: self.profitability_file.close() sys.exit() def best_algo(self): """Retrieves the "bestalgo" from TMB api""" try: data = self.api.bestalgo() # parse json data into variables algo1 = data[0]["algo"] score1 = float(data[0]["score"]) algo2 = data[1]["algo"] score2 = float(data[1]["score"]) self.logger.debug("%s : %f | %s: %f" % (algo1, score1, algo2, score2)) # return result if (score2 - score1) / score1 > self.profitability_threshold: best = algo2 elif (score1 - score2) / score2 > self.profitability_threshold: best = algo1 else: best = None if self.profitability_log: self.profitability_log.writerow({ 'date': datetime.datetime.now(), algo1: score1, algo2: score2 }) self.profitability_file.flush() return best except (socket.error, KeyError): self.logger.warning('Cannot connect to TMB API...') return None # # Return scrypt/nscrypt based on the version of the miner running # # Temporarly disabled to support sgminer since we can't reliably determine # # if sgminer is mining nfactor 10 or 11 # def current_algo(self): # try: # data = self.cgminer.version() # version = data['STATUS'][0]['Description'] # if version.startswith('vertminer'): # vertminer 0.5.4pre1 # return 'nscrypt' # elif version.startswith('cgminer'): # cgminer 3.7.2 # return 'scrypt' # else: # return None # except: # self.logger.warning('Cannot connect to miner API...') # return None def switch_algo(self, algo): """Tells the current miner to exit and start the other one""" self.logger.info('=> Switching to %s (running %s)' % (algo, self.algos[algo].command)) self.current_algo = algo try: self.cgminer.quit() time.sleep(self.switchtime ) # Wait for it to quit / Or check the process id? except socket.error: pass # Cgminer not running try: subprocess.Popen(self.algos[algo].command) except OSError: self.logger.critical('Cannot execute [%s]!' % self.algos[algo].command) self.logger.critical( 'Make sure your miner startup scripts are executable before continuing.' ) sys.exit() def __prepare_logger(self, logging_config={}): """Configure the logger""" logfile = logging_config.get('logfile') # Set console log level based on the config if bool(logging_config.get('verbose')): log_level = logging.DEBUG else: log_level = logging.INFO # Prepare logger self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) ## Console logging # create console handler stream_handler = logging.StreamHandler() stream_handler.setLevel(log_level) # create formatter and add it to the handler formatter = logging.Formatter('%(asctime)s :: %(message)s', "%Y-%m-%d %H:%M:%S") stream_handler.setFormatter(formatter) # add the handler to the logger self.logger.addHandler(stream_handler) ## File logging if logfile: print "Logging to %s" % logfile # create file handler file_handler = logging.FileHandler(logfile, 'a') file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter( '%(asctime)s :: %(levelname)8s :: %(message)s', "%Y-%m-%d %H:%M:%S") file_handler.setFormatter(formatter) self.logger.addHandler(file_handler) csv_file = logging_config.get('profitability_log') if csv_file: self.__prepare_profitability_log(csv_file) def __prepare_profitability_log(self, csv_file): # Check if file is already present to know if we need to write the headers write_header = not (os.path.isfile(csv_file)) self.profitability_file = open(csv_file, 'ab') self.profitability_log = csv.DictWriter(self.profitability_file, ['date', 'scrypt', 'nscrypt']) if write_header: self.profitability_log.writeheader() def __load_config(self): config_file = 'tmb-switcher.conf' # Check if the config file is present if not (os.path.isfile(config_file)): print "ERROR: Configuration file not found!" print "Make sure the tmb-switcher.conf file is present!" sys.exit() # Load the config file config = ConfigParser.ConfigParser() config.read(config_file) # Read the logging settings and setup the logger logging_config = dict(config.items('Logging')) self.__prepare_logger(logging_config) # Read the settings or use default values try: self.api_key = config.get('TradeMyBit', 'apikey') except: self.logger.critical("Could not read apikey from config file") sys.exit() try: self.idletime = config.getint('Misc', 'idletime') except: self.logger.warning( "Could not read idletime from config file. Defaulting to 5 min" ) self.idletime = 5 try: self.switchtime = config.getint('Misc', 'switchtime') except: self.logger.warning( "Could not read switchtime from config file. Defaulting to 1s") self.switchtime = 1 try: self.profitability_threshold = config.getfloat( 'Misc', 'profitability_threshold') except: self.logger.warning( "Could not read profitability_threshold from config file. Defaulting to 10%" ) self.profitability_threshold = 0.1 try: self.cgminer_host = config.get('cgminer', 'host') except: self.logger.warning( "Could not read cgminer host from config file. Defaulting to 127.0.0.1" ) self.cgminer_host = '127.0.0.1' try: self.cgminer_port = config.getint('cgminer', 'port') except: self.logger.warning( "Could not read cgminer port from config file. Defaulting to 4028" ) self.cgminer_host = 4028 for key in self.algos: try: script = config.get('Scripts', key) if os.path.isfile(script): self.algos[key].command = script else: self.logger.critical('Script for %s not found!' % key) self.cleanup() except ConfigParser.NoOptionError: self.logger.warning('Script for %s not configured!' % key) continue
class Cgminer: def __init__(self): self.api = CgminerAPI() self.config_path = os.path.dirname( os.path.realpath(__file__)) + '/config/cgminer' def active(self): output = os.popen('ps x | grep cgminer').read() if re.search('config/cgminer', output): return True return False def start(self): subprocess.Popen(['cgminer', '-c', 'config/cgminer', '-T'], stdout=open('logs', 'w')) def stop(self): subprocess.Popen(['killall', 'cgminer'], stdout=subprocess.PIPE) def restart(self): self.stop() time.sleep(3) self.start() def devices(self): data = {} try: data['edevs'] = self.api.edevs() except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) try: data['estats'] = self.api.estats() except Exception as e: raise CgminerError('Problem with API estats method: ' + e.message) result = [] try: for i in xrange(0, len(data['edevs']['DEVS'])): dev = data['edevs']['DEVS'][i] stat = data['estats']['STATS'][i] result.append({ 'id': dev['ID'], 'name': dev['Name'], 'mhs': dev['MHS 1m'], 'ghs': dev['MHS 1m'] / 1000, 'temperature': dev['Temperature'], 'accepted': dev['Accepted'], 'rejected': dev['Rejected'], 'clockrate': stat['base clockrate'], 'fan': stat['fan percent'], 'voltage': stat['Asic0 voltage 0'] }) except Exception as e: raise CgminerError('Problem with devices data preparing: ' + e.message) return result def summary(self): try: summary = self.api.summary() except Exception as e: raise CgminerError('Problem with API summary method: ' + e.message) try: pools = self.api.pools() except Exception as e: raise CgminerError('Problem with API pools method: ' + e.message) try: edevs = self.api.edevs() except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) try: total = summary['SUMMARY'][0]['Accepted'] + summary['SUMMARY'][0][ 'Rejected'] if total == 0: accepted_percent = 0 rejected_percent = 0 else: accepted_percent = int(summary['SUMMARY'][0]['Accepted'] / total * 100) rejected_percent = int(summary['SUMMARY'][0]['Rejected'] / total * 100) result = { 'mhs': 0, 'ghs': 0, 'accepted': summary['SUMMARY'][0]['Accepted'], 'rejected': summary['SUMMARY'][0]['Rejected'], 'accepted_percent': accepted_percent, 'rejected_percent': rejected_percent, 'pool': { 'url': pools['POOLS'][0]['URL'], 'user': pools['POOLS'][0]['User'] } } for edev in edevs['DEVS']: result['mhs'] += edev['MHS 1m'] result['ghs'] += edev['MHS 1m'] / 1000 except Exception as e: raise CgminerError('Problem with summary data preparing: ' + e.message) return result def pools(self): with open(self.config_path, 'r') as f: return json.loads(f.read())['pools'] # TODO: catch exceptions def update_pools(self, pools): ordered_pools = sorted(pools, key=lambda pool: int(pool['priority'])) with open(self.config_path, 'r') as f: config = json.loads(f.read()) config['pools'] = ordered_pools with open(self.config_path, 'w') as f: json.dump(config, f) def clockrate(self): with open(self.config_path, 'r') as f: return json.loads(f.read())['hfa-hash-clock'] def update_clockrate(self, clockrate): with open(self.config_path, 'r') as f: config = json.loads(f.read()) config['hfa-hash-clock'] = clockrate with open(self.config_path, 'w') as f: json.dump(config, f) def fan_speed(self): with open(self.config_path, 'r') as f: config = json.loads(f.read()) if 'hfa-fan' in config: return config['hfa-fan'] else: return 'auto' def update_fan_speed(self, fan_speed): with open(self.config_path, 'r') as f: config = json.loads(f.read()) if fan_speed == 'auto': if 'hfa-fan' in config: del config['hfa-fan'] else: config['hfa-fan'] = fan_speed with open(self.config_path, 'w') as f: json.dump(config, f) def overheat(self): with open(self.config_path, 'r') as f: return json.loads(f.read())['hfa-temp-overheat'] def update_overheat(self, overheat): with open(self.config_path, 'r') as f: config = json.loads(f.read()) config['hfa-temp-overheat'] = overheat with open(self.config_path, 'w') as f: json.dump(config, f) def save(self): try: print self.api.save(self.config_path) except Exception as e: raise CgminerError('Problem with API save method: ' + e.message) return True def latest_hashrate_poins(self): points = [] try: for edev in self.api.edevs()['DEVS']: points.append(edev['MHS 5m'] / 1000) except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) return points
from pycgminer import CgminerAPI import time,urllib2,json,simplejson,datetime cgminer = CgminerAPI() summary = cgminer.summary() gpu0 = cgminer.gpu(0) gpu1 = cgminer.gpu(1) #print summary #print my_gpu0 #print my_gpu1 gpu0_temp = json.dumps(gpu0) gpu1_temp = json.dumps(gpu1) gpu0_parsed_json = json.loads(gpu0_temp) gpu1_parsed_json = json.loads(gpu1_temp) #gpu0_temperature = gpu0_parsed_json['GPU']['Temperature'] #gpu0_fan_speed = gpu0_parsed_json['GPU']['Fan_Speed'] gpu0_parsed_json_gpu = gpu0_parsed_json['GPU'][0] gpu0_temperature = gpu0_parsed_json_gpu[u'Temperature'] gpu0_fan_speed = gpu0_parsed_json_gpu[u'Fan Speed'] gpu0_fan_percent = gpu0_parsed_json_gpu[u'Fan Percent'] gpu0_rejected = gpu0_parsed_json_gpu[u'Rejected'] gpu0_accepted = gpu0_parsed_json_gpu[u'Accepted'] gpu0_hw_errors = gpu0_parsed_json_gpu[u'Hardware Errors']
class TradeMyBitSwitcher(object): def __init__(self): # Define supported algo self.algos = {} self.profitability_log = None self.__load_config() self.api = TradeMyBitAPI(self.api_key, 'https://pool.trademybit.com/api/') self.cgminer = CgminerAPI(self.cgminer_host, self.cgminer_port) # We track state in a variable self.current_algo = None def main(self): try: print '-' * 72 while True: # get data from sources self.logger.debug("Fetching data...") bestalgo = self.best_algo() self.logger.debug("=> Best: %s | Currently mining: %s" % (bestalgo, self.current_algo)) if bestalgo != self.current_algo and bestalgo != None: # i.e. if we're not already mining the best algo self.switch_algo(bestalgo) elif self.current_algo == None: # TODO: useless? # No miner running and profitability is similar, run the first algo self.logger.warning('No miner running') self.switch_algo(self.algos.keys()[0]) # sleep self.logger.debug('Going to sleep for %d min...' % self.idletime) i = 0 while i < self.idletime * 60: time.sleep(1) i += 1 except KeyboardInterrupt: self.logger.warn('Caught KeyboardInterrupt, terminating...') self.cleanup() def cleanup(self): """Cleanup our mess""" if self.profitability_log: self.profitability_file.close() sys.exit() def best_algo(self): """Retrieves the "bestalgo" from TMB api""" data_dict = {} algolist = [] try: data = self.api.bestalgo() # parse json data into variables scores = {} logString = [] for algo in data: logString.append("%s : %f" % (algo['algo'], float(algo['score']))) if self.algos.has_key(algo['algo']): scores[algo['algo']] = float(algo['score']) self.logger.debug(' | '.join(logString)) # Problem with the API, scores is empty. if not bool(scores): return None # return result best_algo = max(scores.iterkeys(), key=(lambda key: scores[key])) # Switch if not yet mining or we're crossing the threshold if (self.current_algo == None) or \ (self.current_algo == best_algo) or \ (((scores[best_algo] - scores[self.current_algo]) / scores[self.current_algo]) > self.profitability_threshold): best = best_algo else: best = None if self.profitability_log: scores['date'] = datetime.datetime.now() self.profitability_log.writerow(scores) self.profitability_file.flush() return best except (socket.error, KeyError): self.logger.warning('Cannot connect to TMB API...') return None except IndexError: self.logger.warning('Empty TMB API resultset...') return None def switch_algo(self, algo): """Tells the current miner to exit and start the other one""" self.logger.info('=> Switching to %s (running %s)' % (algo, self.algos[algo].command)) self.current_algo = algo try: self.cgminer.quit() time.sleep(self.switchtime) # Wait for it to quit / Or check the process id? except socket.error: pass # Cgminer not running try: subprocess.Popen(self.algos[algo].command) except OSError: self.logger.critical('Cannot execute [%s]!' % self.algos[algo].command) self.logger.critical('Make sure your miner startup scripts are executable before continuing.') sys.exit() def __prepare_logger(self, logging_config={}): """Configure the logger""" logfile = logging_config.get('logfile') # Set console log level based on the config if bool(logging_config.get('verbose')): log_level = logging.DEBUG else: log_level = logging.INFO # Prepare logger self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) ## Console logging # create console handler stream_handler = logging.StreamHandler() stream_handler.setLevel(log_level) # create formatter and add it to the handler formatter = logging.Formatter('%(asctime)s :: %(message)s', "%Y-%m-%d %H:%M:%S") stream_handler.setFormatter(formatter) # add the handler to the logger self.logger.addHandler(stream_handler) # # File logging if logfile: print "Logging to %s" % logfile # create file handler file_handler = logging.FileHandler(logfile, 'a') file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s :: %(levelname)8s :: %(message)s', "%Y-%m-%d %H:%M:%S") file_handler.setFormatter(formatter) self.logger.addHandler(file_handler) def __prepare_profitability_log(self, csv_file): # Check if file is already present to know if we need to write the headers if os.path.isfile(csv_file): os.rename(csv_file, 'profitability-' + time.strftime("%Y%m%d-%H%M%S") + ".csv") # write_header = not(os.path.isfile(csv_file)) self.profitability_file = open(csv_file, 'ab') csv_header = ['date'] for algo in self.algos: csv_header.append(algo) self.profitability_log = csv.DictWriter(self.profitability_file, ['date'] + self.algos.keys()) # if write_header: self.profitability_log.writeheader() def __load_config(self): config_file = 'tmb-switcher.conf' # Check if the config file is present if not(os.path.isfile(config_file)): print "ERROR: Configuration file not found!" print "Make sure the tmb-switcher.conf file is present!" sys.exit() # Load the config file config = ConfigParser.ConfigParser() config.read(config_file) # Read the logging settings and setup the logger logging_config = dict(config.items('Logging')) self.__prepare_logger(logging_config) # Read the settings or use default values try: self.api_key = config.get('TradeMyBit', 'apikey') except: self.logger.critical("Could not read apikey from config file") sys.exit() try: self.idletime = config.getint('Misc', 'idletime') except: self.logger.warning("Could not read idletime from config file. Defaulting to 5 min") self.idletime = 5 try: self.switchtime = config.getint('Misc', 'switchtime') except: self.logger.warning("Could not read switchtime from config file. Defaulting to 1s") self.switchtime = 1 try: self.profitability_threshold = config.getfloat('Misc', 'profitability_threshold') except: self.logger.warning("Could not read profitability_threshold from config file. Defaulting to 10%") self.profitability_threshold = 0.1 try: self.cgminer_host = config.get('cgminer', 'host') except: self.logger.warning("Could not read cgminer host from config file. Defaulting to 127.0.0.1") self.cgminer_host = '127.0.0.1' try: self.cgminer_port = config.getint('cgminer', 'port') except: self.logger.warning("Could not read cgminer port from config file. Defaulting to 4028") self.cgminer_host = 4028 for key in dict(config.items('Scripts')): try: script = config.get('Scripts', key) if os.path.isfile(script): self.algos[key] = Algo(key) self.algos[key].command = script else: self.logger.critical('Script for %s not found!' % key) self.cleanup() except ConfigParser.NoOptionError : self.logger.warning('Script for %s not configured!' % key) continue self.logger.debug("Enabled algorithms: %s" % ', '.join(self.algos.keys())) if not self.algos: self.logger.critical('No mining algorithms enabled!') sys.exit() csv_file = logging_config.get('profitability_log') if csv_file: self.__prepare_profitability_log(csv_file)
class Cgminer: def __init__(self): self.api = CgminerAPI() def devices(self): data = {} try: data['edevs'] = self.api.edevs() except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) try: data['estats'] = self.api.estats() except Exception as e: raise CgminerError('Problem with API estats method: ' + e.message) result = [] try: for i in xrange(0, len(data['edevs']['DEVS'])): dev = data['edevs']['DEVS'][i] stat = data['estats']['STATS'][i] result.append({ 'id': dev['ID'], 'name': dev['Name'], 'mhs': dev['MHS 5m'], 'ghs': dev['MHS 5m'] / 1000, 'temperature': dev['Temperature'], 'accepted': dev['Accepted'], 'rejected': dev['Rejected'], 'clockrate': stat['base clockrate'], 'fan': stat['fan percent'], 'voltage': stat['Asic0 voltage 0'] }) except Exception as e: raise CgminerError('Problem with devices data preparing: ' + e.message) return result def summary(self): try: summary = self.api.summary() except Exception as e: raise CgminerError('Problem with API summary method: ' + e.message) try: pools = self.api.pools() except Exception as e: raise CgminerError('Problem with API pools method: ' + e.message) try: total = summary['SUMMARY'][0]['Accepted'] + summary['SUMMARY'][0]['Rejected'] accepted_percent = int(summary['SUMMARY'][0]['Accepted'] / total * 100) rejected_percent = int(summary['SUMMARY'][0]['Rejected'] / total * 100) result = { 'mhs': summary['SUMMARY'][0]['MHS 5m'], 'ghs': summary['SUMMARY'][0]['MHS 5m'] / 1000, 'accepted': summary['SUMMARY'][0]['Accepted'], 'rejected': summary['SUMMARY'][0]['Rejected'], 'accepted_percent': accepted_percent, 'rejected_percent': rejected_percent, 'pool': { 'url': pools['POOLS'][0]['URL'], 'user': pools['POOLS'][0]['User'] } } except Exception as e: raise CgminerError('Problem with preparing data: ' + e.message) return result def save(self, file_path): try: print self.api.save(file_path) except Exception as e: raise CgminerError('Problem with API save method: ' + e.message) return True def latest_hashrate_poins(self): points = [] try: for edev in self.api.edevs()['DEVS']: points.append(edev['MHS 5m'] / 1000) except Exception as e: raise CgminerError('Problem with API edevs method: ' + e.message) return points
#!/usr/bin/python import json import urllib from pycgminer import CgminerAPI LTC_TIMEOUT = 10800 TAG_TIMEOUT = 900 cgminer = CgminerAPI() tag_hash_faster_link = 'http://tag.hashfaster.com/index.php?page=api&action=gettimesincelastblock&api_key=29c14a879e901f304a82fa5b97735b7c0032638cce8e3bd54e6d9e7bf8f8e9e6&id=488' ltc_hash_faster_link = 'http://ltc.hashfaster.com/index.php?page=api&action=gettimesincelastblock&api_key=40a66486837fd754d275475eefcf6d4bac86e8928cc2312ac34c55cc4e824440&id=1305' f = urllib.urlopen(tag_hash_faster_link) tag_hash_faster_json = f.read() f = urllib.urlopen(ltc_hash_faster_link) ltc_hash_faster_json = f.read() decoded_tag = json.loads(tag_hash_faster_json) decoded_ltc = json.loads(ltc_hash_faster_json) tag_time = decoded_tag['gettimesincelastblock']['data'] ltc_time = decoded_ltc['gettimesincelastblock'] if ltc_time < LTC_TIMEOUT: print cgminer.switchpool(0) elif tag_time < TAG_TIMEOUT: print cgminer.switchpool(5) else: print cgminer.switchpool(1)
def __init__(self, config): self.config = config self.cgminer = CgminerAPI(config['cgminer']['host'], config['cgminer']['port']) self.coinwarz = CoinwarzAPI(config['coinwarz']) self.cryptsy = CryptsyAPI(config['cryptsy']) self.hashrate = self.config['hashrate']
class CPC(object): def __init__(self, config): self.config = config self.cgminer = CgminerAPI(config['cgminer']['host'], config['cgminer']['port']) self.coinwarz = CoinwarzAPI(config['coinwarz']) self.cryptsy = CryptsyAPI(config['cryptsy']) self.hashrate = self.config['hashrate'] def restart_cgminer(self): logger.info('Restarting CGMiner...') try: self.cgminer.restart() except ValueError: pass while True: try: self.cgminer.version() except socket.error: time.sleep(1) else: break logger.info('CGMiner restarted') def cgminer_pools(self): pools = [] for pool in self.cgminer.pools()['POOLS']: currency = self.config['pool_currency'].get(pool['URL']) if pool['Status'] != 'Alive': logger.warning('Pool %s status is %s', pool['URL'], pool['Status']) if not currency: logger.error('Unknown currency for pool %s', pool['URL']) continue pool['Currency'] = currency pools.append(pool) return pools def get_currencies(self): currencies = {} btc_price = None price_data = self.cryptsy.get_data()['return']['markets'] difficulty_data = self.coinwarz.get_data()['Data'] for label, currency_price_data in price_data.items(): if currency_price_data['secondarycode'] != 'BTC': continue currency_data = currencies[currency_price_data['primarycode']] = {} currency_data['id'] = currency_price_data['primarycode'] currency_data['name'] = currency_price_data['primaryname'] currency_data['price'] = float(currency_price_data['lasttradeprice']) currency_data['exchange_volume'] = float(currency_price_data['volume']) for currency_difficulty_data in difficulty_data: currency = currency_difficulty_data['CoinTag'] if currency == 'BTC': btc_price = currency_difficulty_data['ExchangeRate'] continue if currency not in currencies: continue currency_data = currencies[currency] currency_data['profit_growth'] = currency_difficulty_data['ProfitRatio'] / currency_difficulty_data['AvgProfitRatio'] currency_data['difficulty'] = currency_difficulty_data['Difficulty'] currency_data['block_reward'] = currency_difficulty_data['BlockReward'] currency_data['coins_per_day'] = 86400 * self.hashrate * currency_data['block_reward'] / (currency_data['difficulty'] * 2 ** 32) currencies = {k: v for k, v in currencies.iteritems() if 'coins_per_day' in v} for currency_data in currencies.values(): currency_data['usd_per_day'] = currency_data['coins_per_day'] * currency_data['price'] * btc_price currency_data['rating'] = RatingCalculator.rate_currency(currency_data) return currencies
class TradeMyBitSwitcher(object): def __init__(self): # Define supported algo self.algos = {} self.profitability_log = None self.__load_config() self.api = TradeMyBitAPI(self.api_key, 'https://pool.trademybit.com/api/') self.cgminer = CgminerAPI(self.cgminer_host, self.cgminer_port) # We track state in a variable self.current_algo = None def main(self): try: print '-' * 72 while True: # get data from sources self.logger.debug("Fetching data...") bestalgo = self.best_algo() self.logger.debug("=> Best: %s | Currently mining: %s" % (bestalgo, self.current_algo)) if bestalgo != self.current_algo and bestalgo != None: # i.e. if we're not already mining the best algo self.switch_algo(bestalgo) elif self.current_algo == None: # TODO: useless? # No miner running and profitability is similar, run the first algo self.logger.warning('No miner running') self.switch_algo(self.algos.keys()[0]) # sleep self.logger.debug('Going to sleep for %d min...' % self.idletime) i = 0 while i < self.idletime * 60: time.sleep(1) i += 1 except KeyboardInterrupt: self.logger.warn('Caught KeyboardInterrupt, terminating...') self.cleanup() def cleanup(self): """Cleanup our mess""" if self.profitability_log: self.profitability_file.close() sys.exit() def best_algo(self): """Retrieves the "bestalgo" from TMB api""" data_dict = {} algolist = [] try: data = self.api.bestalgo() # parse json data into variables scores = {} logString = [] for algo in data: logString.append("%s : %f" % (algo['algo'], float(algo['score']))) if self.algos.has_key(algo['algo']): scores[algo['algo']] = float(algo['score']) self.logger.debug(' | '.join(logString)) # Problem with the API, scores is empty. if not bool(scores): return None # return result best_algo = max(scores.iterkeys(), key=(lambda key: scores[key])) # Switch if not yet mining or we're crossing the threshold if (self.current_algo == None) or \ (self.current_algo == best_algo) or \ (((scores[best_algo] - scores[self.current_algo]) / scores[self.current_algo]) > self.profitability_threshold): best = best_algo else: best = None if self.profitability_log: scores['date'] = datetime.datetime.now() self.profitability_log.writerow(scores) self.profitability_file.flush() return best except (socket.error, KeyError): self.logger.warning('Cannot connect to TMB API...') return None except IndexError: self.logger.warning('Empty TMB API resultset...') return None def switch_algo(self, algo): """Tells the current miner to exit and start the other one""" self.logger.info('=> Switching to %s (running %s)' % (algo, self.algos[algo].command)) self.current_algo = algo try: self.cgminer.quit() time.sleep(self.switchtime ) # Wait for it to quit / Or check the process id? except socket.error: pass # Cgminer not running try: subprocess.Popen(self.algos[algo].command) except OSError: self.logger.critical('Cannot execute [%s]!' % self.algos[algo].command) self.logger.critical( 'Make sure your miner startup scripts are executable before continuing.' ) sys.exit() def __prepare_logger(self, logging_config={}): """Configure the logger""" logfile = logging_config.get('logfile') # Set console log level based on the config if bool(logging_config.get('verbose')): log_level = logging.DEBUG else: log_level = logging.INFO # Prepare logger self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) ## Console logging # create console handler stream_handler = logging.StreamHandler() stream_handler.setLevel(log_level) # create formatter and add it to the handler formatter = logging.Formatter('%(asctime)s :: %(message)s', "%Y-%m-%d %H:%M:%S") stream_handler.setFormatter(formatter) # add the handler to the logger self.logger.addHandler(stream_handler) # # File logging if logfile: print "Logging to %s" % logfile # create file handler file_handler = logging.FileHandler(logfile, 'a') file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter( '%(asctime)s :: %(levelname)8s :: %(message)s', "%Y-%m-%d %H:%M:%S") file_handler.setFormatter(formatter) self.logger.addHandler(file_handler) def __prepare_profitability_log(self, csv_file): # Check if file is already present to know if we need to write the headers if os.path.isfile(csv_file): os.rename( csv_file, 'profitability-' + time.strftime("%Y%m%d-%H%M%S") + ".csv") # write_header = not(os.path.isfile(csv_file)) self.profitability_file = open(csv_file, 'ab') csv_header = ['date'] for algo in self.algos: csv_header.append(algo) self.profitability_log = csv.DictWriter(self.profitability_file, ['date'] + self.algos.keys()) # if write_header: self.profitability_log.writeheader() def __load_config(self): config_file = 'tmb-switcher.conf' # Check if the config file is present if not (os.path.isfile(config_file)): print "ERROR: Configuration file not found!" print "Make sure the tmb-switcher.conf file is present!" sys.exit() # Load the config file config = ConfigParser.ConfigParser() config.read(config_file) # Read the logging settings and setup the logger logging_config = dict(config.items('Logging')) self.__prepare_logger(logging_config) # Read the settings or use default values try: self.api_key = config.get('TradeMyBit', 'apikey') except: self.logger.critical("Could not read apikey from config file") sys.exit() try: self.idletime = config.getint('Misc', 'idletime') except: self.logger.warning( "Could not read idletime from config file. Defaulting to 5 min" ) self.idletime = 5 try: self.switchtime = config.getint('Misc', 'switchtime') except: self.logger.warning( "Could not read switchtime from config file. Defaulting to 1s") self.switchtime = 1 try: self.profitability_threshold = config.getfloat( 'Misc', 'profitability_threshold') except: self.logger.warning( "Could not read profitability_threshold from config file. Defaulting to 10%" ) self.profitability_threshold = 0.1 try: self.cgminer_host = config.get('cgminer', 'host') except: self.logger.warning( "Could not read cgminer host from config file. Defaulting to 127.0.0.1" ) self.cgminer_host = '127.0.0.1' try: self.cgminer_port = config.getint('cgminer', 'port') except: self.logger.warning( "Could not read cgminer port from config file. Defaulting to 4028" ) self.cgminer_host = 4028 for key in dict(config.items('Scripts')): try: script = config.get('Scripts', key) if os.path.isfile(script): self.algos[key] = Algo(key) self.algos[key].command = script else: self.logger.critical('Script for %s not found!' % key) self.cleanup() except ConfigParser.NoOptionError: self.logger.warning('Script for %s not configured!' % key) continue self.logger.debug("Enabled algorithms: %s" % ', '.join(self.algos.keys())) if not self.algos: self.logger.critical('No mining algorithms enabled!') sys.exit() csv_file = logging_config.get('profitability_log') if csv_file: self.__prepare_profitability_log(csv_file)
def __init__(self): self.api = CgminerAPI() self.config_path = os.path.dirname( os.path.realpath(__file__)) + '/config/cgminer'
def __init__(self): self.api = CgminerAPI()