i just did an small mod to the phoenix code, to export the hashrate to a plain text file... i did it to make remote monitoring easier.
phoenix.py
#!/usr/bin/python
# Copyright (C) 2011 by jedi95 and
# CFSworks
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import imp
from sys import exit
from twisted.internet import reactor
from optparse import OptionParser
import minerutil
from ConsoleLogger import ConsoleLogger
from WorkQueue import WorkQueue
from Miner import Miner
class CommandLineOptions(object):
"""Implements the Options interface for user-specified command-line
arguments.
"""
def __init__(self):
self.parsedSettings = None
self.url = None
self.logger = None
self.connection = None
self.kernel = None
self.queue = None
self.logtotext = None
self.kernelOptions = {}
self._parse()
def _parse(self):
parser = OptionParser(usage="%prog -u URL [-k kernel] [kernel params]")
parser.add_option("-v", "--verbose", action="store_true",
dest="verbose", default=False, help="show debug messages")
parser.add_option("-k", "--kernel", dest="kernel", default="poclbm",
help="the name of the kernel to use")
parser.add_option("-u", "--url", dest="url", default=None,
help="the URL of the mining server to work for [REQUIRED]")
parser.add_option("-q", "--queuesize", dest="queuesize", type="int",
default=1, help="how many work units to keep queued at all times")
parser.add_option("-a", "--avgsamples", dest="avgsamples", type="int",
default=10,
help="how many samples to use for hashrate average"),
parser.add_option("-l", "--logtotext", dest="logtotext", default="none")
self.parsedSettings, args = parser.parse_args()
if self.parsedSettings.url is None:
parser.print_usage()
exit()
else:
self.url = self.parsedSettings.url
for arg in args:
self._kernelOption(arg)
def getQueueSize(self):
return self.parsedSettings.queuesize
def getAvgSamples(self):
return self.parsedSettings.avgsamples
def _kernelOption(self, arg):
pair = arg.split('=',1)
if len(pair) < 2:
pair.append(None)
var, value = tuple(pair)
self.kernelOptions[var.upper()] = value
def makeLogger(self, requester, miner):
if not self.logger:
self.logger = ConsoleLogger(miner,self.parsedSettings.verbose,self.parsedSettings.logtotext)
return self.logger
def makeConnection(self, requester):
if not self.connection:
try:
self.connection = minerutil.openURL(self.url, requester)
except ValueError, e:
print(e)
exit()
return self.connection
def makeKernel(self, requester):
if not self.kernel:
module = self.parsedSettings.kernel
try:
file, filename, smt = imp.find_module(module, ['kernels'])
except ImportError:
print("Could not locate the specified kernel!")
exit()
kernelModule = imp.load_module(module, file, filename, smt)
self.kernel = kernelModule.MiningKernel(requester)
return self.kernel
def makeQueue(self, requester):
if not self.queue:
self.queue = WorkQueue(requester, self)
return self.queue
if __name__ == '__main__':
options = CommandLineOptions()
miner = Miner()
miner.start(options)
reactor.run()
ConsoleLogger.py
# Copyright (C) 2011 by jedi95 and
# CFSworks
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import sys
from time import time
from datetime import datetime
def formatNumber(n):
"""Format a positive integer in a more readable fashion."""
if n < 0:
raise ValueError('can only format positive integers')
prefixes = 'KMGTP'
whole = str(int(n))
decimal = ''
i = 0
while len(whole) > 3:
if i + 1 < len(prefixes):
decimal = '.%s' % whole[-3:-1]
whole = whole[:-3]
i += 1
else:
break
return '%s%s %s' % (whole, decimal, prefixes[i])
class ConsoleLogger(object):
"""This class will handle printing messages to the console."""
TIME_FORMAT = '[%d/%m/%Y %H:%M:%S]'
UPDATE_TIME = 1.0
def __init__(self, miner, verbose=False, logtotext="none"):
self.verbose = verbose
self.miner = miner
self.logtotext = logtotext
self.lastUpdate = time() - 1
self.rate = 0
self.accepted = 0
self.invalid = 0
self.lineLength = 0
self.connectionType = None
def reportRate(self, rate, update=True):
"""Used to tell the logger the current Khash/sec."""
self.rate = rate
if update:
self.updateStatus()
def reportType(self, type):
self.connectionType = type
def reportBlock(self, block):
self.log('Currently on block: ' + str(block))
def reportFound(self, hash, accepted):
if accepted:
self.accepted += 1
else:
self.invalid += 1
hexHash = hash[::-1]
hexHash = hexHash[:8].encode('hex')
if self.verbose:
self.log('Result %s... %s' % (hexHash,
'accepted' if accepted else 'rejected'))
else:
self.log('Result: %s %s' % (hexHash[8:],
'accepted' if accepted else 'rejected'))
def reportMsg(self, message):
self.log(('MSG: ' + message), True, True)
def reportConnected(self, connected):
if connected:
self.log('Connected to server')
else:
self.log('Disconnected from server')
def reportConnectionFailed(self):
self.log('Failed to connect, retrying...')
def reportDebug(self, message):
if self.verbose:
self.log(message)
def updateStatus(self, force=False):
#only update if last update was more than a second ago
dt = time() - self.lastUpdate
if force or dt > self.UPDATE_TIME:
rate = self.rate if (not self.miner.idle) else 0
type = " [" + str(self.connectionType) + "]" if self.connectionType is not None else ''
status = (
"[" + formatNumber(rate) + "hash/sec] "
"[" + str(self.accepted) + " Accepted] "
"[" + str(self.invalid) + " Rejected]" + type)
self.say(status)
if self.logtotext != "none":
try:
f = open(self.logtotext,"w")
f.write(status)
f.close()
except IOError as e:
print("({})".format(e))
self.lastUpdate = time()
def say(self, message, newLine=False, hideTimestamp=False):
#add new line if requested
if newLine:
message += '\n'
if hideTimestamp:
timestamp = ''
else:
timestamp = datetime.now().strftime(self.TIME_FORMAT) + ' '
message = timestamp + message
#erase the previous line
if self.lineLength > 0:
sys.stdout.write('\b \b' * self.lineLength)
sys.stdout.write(' ' * self.lineLength)
sys.stdout.write('\b \b' * self.lineLength)
#print the line
sys.stdout.write(message)
sys.stdout.flush()
#cache the current line length
if newLine:
self.lineLength = 0
else:
self.lineLength = len(message)
def log(self, message, update=True, hideTimestamp=False):
self.say(message, True, hideTimestamp)
if update:
self.updateStatus(True)
Added new command line argument: -l filename.txt
What it does is to export "status(hashrate and other stats)" to a plain text file, in a single line for easier use.
Like this:
[400.31 Mhash/sec] [0 Accepted] [0 Rejected] [RPC]
You can use routes too, like this -l /usr/hashrate.txt, but you going to need to run the miner with sudo.
It seems to be working fine.