poclbm
poclbm copied to clipboard
Start mining when the screensaver is activated
Hi there
I just hacked together a little something that polls dbus and starts/stops mining when the screensaver comes on/off.
My editor removes whitespace at line ends so there's a few occurrences of that in the diff. This will of course only work on systems with dbus. Since I'm really not a python programmer I'd like to leave the task of making this safe for other platforms (e.g. disabled) and maybe adding a console switch to (de)activate this feature or add a checkbox in the gui and whatnot to you.
For my purposes, this is sufficient but I hope it might be useful to others and so am trying to contribute back.
Have fun!
diff --git a/guiminer.py b/guiminer.py
old mode 100644
new mode 100755
index e8c9499..780fe7a
--- a/guiminer.py
+++ b/guiminer.py
@@ -1,3 +1,5 @@
+#!/usr/bin/python
+
"""GUIMiner - graphical frontend to Bitcoin miners.
Currently supports:
@@ -14,6 +16,7 @@ import sys, os, subprocess, errno, re, threading, logging, time, httplib, urllib
import wx
import json
import collections
+import dbus
try:
import win32api, win32con, win32process
@@ -165,7 +168,7 @@ def get_opencl_devices():
for i, platform in enumerate(platforms):
devices = platform.get_devices()
for j, device in enumerate(devices):
- device_strings.append('[%d-%d] %s' %
+ device_strings.append('[%d-%d] %s' %
(i, j, merge_whitespace(device.name)[:25]))
if len(device_strings) == 0:
raise IOError
@@ -227,9 +230,9 @@ logger, formatter = init_logger()
def http_request(hostname, *args, **kwargs):
"""Do a HTTP request and return the response data."""
- conn_cls = httplib.HTTPSConnection if kwargs.get('use_https') else httplib.HTTPConnection
- conn = conn_cls(hostname)
- try:
+ conn_cls = httplib.HTTPSConnection if kwargs.get('use_https') else httplib.HTTPConnection
+ conn = conn_cls(hostname)
+ try:
logger.debug(_("Requesting balance: %(request)s"), dict(request=args))
conn.request(*args)
response = conn.getresponse()
@@ -294,11 +297,11 @@ class ConsolePanel(wx.Panel):
def append_text(self, text):
self.text.AppendText(text)
- lines_to_cut = self.text.GetNumberOfLines() - self.n_max_lines
+ lines_to_cut = self.text.GetNumberOfLines() - self.n_max_lines
if lines_to_cut > 0:
contents = self.text.GetValue()
position = find_nth(contents, '\n', lines_to_cut)
- self.text.ChangeValue(contents[position + 1:])
+ self.text.ChangeValue(contents[position + 1:])
def write(self, text):
"""Forward logging events to our TextCtrl."""
@@ -501,7 +504,7 @@ class PhoenixListenerThread(MinerListenerThread):
(r"Currently on block",
lambda _: None), # Just ignore lines like these
]
-
+
class CgListenerThread(MinerListenerThread):
LINES = [
(r"Accepted .* GPU \d+ thread \d+",
@@ -513,7 +516,7 @@ class CgListenerThread(MinerListenerThread):
(r"^GPU\s*\d+",
lambda _: None), # Just ignore lines like these
]
-
+
class MinerTab(wx.Panel):
"""A tab in the GUI representing a miner instance.
@@ -806,13 +809,13 @@ class MinerTab(wx.Panel):
text = format_khash(self.last_rate)
self.summary_status.SetLabel(text)
- self.summary_shares_accepted.SetLabel("%d (%d)" %
+ self.summary_shares_accepted.SetLabel("%d (%d)" %
(self.accepted_shares, len(self.accepted_times)))
if self.is_solo:
self.summary_shares_invalid.SetLabel("-")
else:
- self.summary_shares_invalid.SetLabel("%d (%d)" %
+ self.summary_shares_invalid.SetLabel("%d (%d)" %
(self.invalid_shares, len(self.invalid_times)))
self.summary_start.SetLabel(self.get_start_stop_state())
@@ -987,7 +990,7 @@ class MinerTab(wx.Panel):
# use universal_newlines to catch the \r output on Mhash/s lines
try:
logger.debug(_('Running command: ') + cmd)
- # for cgminer:
+ # for cgminer:
# We need only the STDOUT for meaningful messages.
if conf_func == self.configure_subprocess_cgminer:
self.miner = subprocess.Popen(cmd, cwd=cwd,
@@ -1003,7 +1006,7 @@ class MinerTab(wx.Panel):
universal_newlines=True,
creationflags=flags,
shell=(sys.platform != 'win32'))
-
+
except OSError:
raise #TODO: the folder or exe could not exist
self.miner_listener = listener_cls(self, self.miner)
@@ -1321,14 +1324,14 @@ For cgminer use -I 8 or -I 9. Without any params for desktop usage."""))
"mtred.com",
"rr.btcmp.com",
"bitcoin-server.de"]
- if host in HOSTS_REQUIRING_AUTH_TOKEN: return True
- if "btcguild" in host: return True
+ if host in HOSTS_REQUIRING_AUTH_TOKEN: return True
+ if "btcguild" in host: return True
return False
-
+
def requires_https(self, host):
"""Return True if the specified host requires HTTPs for balance update."""
return host == "mtred.com"
-
+
def on_balance_refresh(self, event=None):
"""Refresh the miner's balance from the server."""
host = self.server_config.get("host")
@@ -1388,14 +1391,14 @@ For cgminer use -I 8 or -I 9. Without any params for desktop usage."""))
self.http_thread.start() # TODO: look at aliasing of this variable
def request_payout_btcmp(self, balance_auth_token):
- """Request payout from btcmp's server via HTTP POST."""
+ """Request payout from btcmp's server via HTTP POST."""
response, data = http_request(
self.server_config['balance_host'],
"GET",
self.server_config["payout_url"] % balance_auth_token,
use_https=False
)
-
+
if self.is_auth_token_rejected(response):
data = _("Auth token rejected by server.")
elif not data:
@@ -1870,7 +1873,7 @@ class GUIMiner(wx.Frame):
self.Bind(wx.EVT_MENU, self.launch_solo_server, id=ID_LAUNCH)
self.Bind(wx.EVT_MENU, self.on_change_language, id=ID_CHANGE_LANGUAGE)
self.Bind(wx.EVT_MENU, self.on_donate, id=ID_DONATE_SMALL)
- self.Bind(wx.EVT_CLOSE, self.on_close)
+ self.Bind(wx.EVT_CLOSE, self.on_close)
self.Bind(wx.EVT_ICONIZE, self.on_iconize)
self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.on_page_closing)
self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CLOSED, self.on_page_closed)
@@ -1881,7 +1884,7 @@ class GUIMiner(wx.Frame):
if not self.start_minimized_chk.IsChecked():
self.Show()
-
+
def on_iconize(self, event):
if event.Iconized() and sys.platform == 'win32':
self.Hide() # On minimize, hide from taskbar.
@@ -2005,6 +2008,10 @@ class GUIMiner(wx.Frame):
self.Hide()
event.Veto()
else:
+
+ # terminate the dbus mainloop
+ dbusThread.stop()
+
if any(p.is_modified for p in self.profile_panels):
dialog = wx.MessageDialog(self, _('Do you want to save changes?'), _('Save'),
wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
@@ -2100,7 +2107,7 @@ class GUIMiner(wx.Frame):
if config_data.get('show_console', False):
self.show_console()
-
+
window_position = config_data.get('window_position')
if window_position:
self.SetRect(window_position)
@@ -2261,7 +2268,7 @@ class GUIMiner(wx.Frame):
"""Duplicate the current miner to another miner."""
p = self.nb.GetPage(self.nb.GetSelection())
if p not in self.profile_panels:
- return
+ return
self.name_new_profile(event=None, extra_profile_data=p.get_data())
def on_change_language(self, event):
@@ -2304,7 +2311,7 @@ class DonateDialog(wx.Dialog):
data.SetText(DONATION_ADDRESS)
wx.TheClipboard.SetData(data)
wx.TheClipboard.Close()
-
+
class ChangeLanguageDialog(wx.Dialog):
"""Dialog prompting the user to change languages."""
@@ -2385,7 +2392,7 @@ To remember this token for the future, save your miner settings.""")
class AboutGuiminer(wx.Dialog):
"""About dialog for the app with a donation address."""
-
+
def __init__(self, parent, id, title):
wx.Dialog.__init__(self, parent, id, title)
vbox = wx.BoxSizer(wx.VERTICAL)
@@ -2436,10 +2443,58 @@ class OpenCLWarningDialog(wx.Dialog):
def is_box_checked(self):
return self.no_show_chk.GetValue()
+# have a thread that polls the screensaver status from dbus. polling sucks but
+# apparently it is not possible to have 2 mainloops (the app/window already has
+# one and dbus requires to have another one if we want to be a signal (event)
+# receiver.
+class DbusThread(threading.Thread):
+ def run(self):
+ print('starting dbus integration')
+ self.keep_running = True
+ bus = dbus.SessionBus()
+ ss = bus.get_object('org.freedesktop.ScreenSaver', '/ScreenSaver')
+ lastVal = ss.GetActive()
+ while self.keep_running:
+ try:
+ time.sleep(1)
+ val = bool(ss.GetActive())
+ if lastVal != val:
+ print('Screensaver Active = %r' % val)
+ if val == True:
+ for p in frame_1.profile_panels:
+ if p.is_mining:
+ print('Already Mining, No Change')
+ else:
+ print('Mining Start!')
+ wx.CallAfter(p.start_mining)
+ else:
+ for p in frame_1.profile_panels:
+ if p.is_mining:
+ print('Mining Stop!')
+ wx.CallAfter(p.stop_mining)
+ else:
+ print('Not Mining, No Change')
+
+ lastVal = val
+ except Exception, e:
+ logging.exception("Exception: %r" % e)
+
+ print('dbus main loop has finished')
+
+ def stop(self):
+ print('stopping dbus integration')
+ self.keep_running = False
+
+
+# the dbus thread must be able to access frame_1.profile_panels
+frame_1 = GUIMiner(None, -1, "")
+
+# the on close method of the frame must be able to stop the dbus thread
+dbusThread = DbusThread()
def run():
try:
- frame_1 = GUIMiner(None, -1, "")
+ dbusThread.start()
app.SetTopWindow(frame_1)
app.MainLoop()
except:
Nifty, thanks for the contribution! I'm not sure when this will make it into a release, but I'll keep it in the issue tracker for now in case anyone else wants to use it :)
Cool! Great to hear you like it :)
Why don't you fork it and give it a file name and a good description. At least that's what I did when I tried to put up an update the servers list . I'm trying to find an issue on here and it seem to have disappeared since I noticed it. I hope you can find a way to wind this into a screen saver if not directly into guiMiner.