poclbm icon indicating copy to clipboard operation
poclbm copied to clipboard

Start mining when the screensaver is activated

Open stackmagic opened this issue 12 years ago • 3 comments

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:

stackmagic avatar Oct 03 '12 15:10 stackmagic

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 :)

Kiv avatar Oct 03 '12 16:10 Kiv

Cool! Great to hear you like it :)

stackmagic avatar Oct 03 '12 17:10 stackmagic

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.

techman05 avatar May 06 '13 00:05 techman05