├── .htaccess ├── README.md ├── etc └── rc.local ├── opt └── scripta │ ├── README.md │ ├── bin │ ├── bfgminer │ ├── bfgminer-rpc │ ├── cgminer │ ├── cgminer-gc3355 │ ├── cgminer-monitor.py │ ├── cgminer_x8_lite │ └── wdog.py │ ├── etc │ ├── bfgminer.conf │ ├── cron.d │ │ ├── 5min │ │ │ ├── ALERTdeviceCount │ │ │ ├── ALERThashrate │ │ │ ├── hashrate │ │ │ ├── inc │ │ │ └── temp │ │ └── hourly │ │ │ └── donate │ ├── miner.conf │ ├── miner.options.json │ ├── miner.pools.json │ ├── scripta.conf │ ├── uipasswd │ └── version │ ├── http │ └── rrd │ │ ├── mhsav-day.png │ │ ├── mhsav-hour.png │ │ ├── mhsav-month.png │ │ ├── mhsav-week.png │ │ └── mhsav-year.png │ ├── lib │ ├── libblkmaker-0.1.la │ ├── libblkmaker-0.1.so │ ├── libblkmaker-0.1.so.0 │ ├── libblkmaker-0.1.so.0.3.1 │ ├── libblkmaker-0.1.so.0.4.0 │ ├── libblkmaker-0.1.so.0.4.1 │ ├── libblkmaker_jansson-0.1.la │ ├── libblkmaker_jansson-0.1.so │ ├── libblkmaker_jansson-0.1.so.0 │ ├── libblkmaker_jansson-0.1.so.0.3.1 │ ├── libblkmaker_jansson-0.1.so.0.4.0 │ ├── libblkmaker_jansson-0.1.so.0.4.1 │ ├── libusb-1.0.a │ ├── libusb-1.0.la │ ├── libusb-1.0.so │ ├── libusb-1.0.so.2 │ ├── libusb-1.0.so.2.0.0 │ └── pkgconfig │ │ ├── libblkmaker_jansson-0.1.pc │ │ └── libusb-1.0.pc │ ├── modules │ ├── PiMiner │ │ ├── LICENSE.txt │ │ ├── PiMiner.py │ │ ├── PiMinerDisplay.py │ │ ├── PiMinerInfo.py │ │ └── README.md │ └── cgminerLCDStats │ │ ├── CgminerRPCClient.py │ │ ├── MinePeon Install.md │ │ ├── README.md │ │ ├── cgminerLCDStats.py │ │ ├── lcd_and_pi-small.jpg │ │ ├── lcd_and_pi.jpg │ │ └── pylcdsysinfo.py │ ├── startup │ ├── miner-start.sh │ └── miner-stop.sh │ └── var │ └── rrd │ └── .keep ├── update.sh └── var ├── spool └── cron │ └── crontabs │ └── root └── www ├── apple-touch-icon-precomposed.png ├── css ├── alertify.css ├── bootstrap.min.css ├── bootstrap.no-icons.min.css ├── custom.css ├── font-awesome.min.css └── theme.css ├── f_backup.php ├── f_graph.php ├── f_hostHardCtl.php ├── f_login.php ├── f_logout.php ├── f_miner.php ├── f_minerHardCtl.php ├── f_minercompat.php ├── f_settings copy.php ├── f_settings.php ├── f_status.php ├── favicon.ico ├── img ├── bg-header1.png ├── favicon-1.ico ├── favicon-1.png ├── favicon.ico ├── favicon.png ├── scripta-logo-152.png └── scripta-logo-ext-152.png ├── inc ├── ChromePhp.php ├── backup.inc.php ├── bfgminer.inc.php ├── functions.inc.php ├── host.inc.php ├── kitten.mp3 ├── kitten.wav ├── miner.inc.php └── settings.inc.php ├── index.html ├── index.lighttpd.html ├── index.php ├── info.php ├── js ├── alertify.min.js ├── angular.min.js ├── bootstrap.min.js ├── highcharts.js └── jquery.min.js ├── lighttpd.pem ├── login.php ├── miner.php ├── miner_copy.php ├── ng ├── app.js ├── controllers.js ├── directives.js ├── filters.js └── services.js ├── partials ├── backup.html ├── miner.html ├── settings.html ├── status.html └── timezone.html ├── rrd ├── test.php └── update ├── .updatelog ├── ctrl.php ├── start.php ├── update.php └── version.php /.htaccess: -------------------------------------------------------------------------------- 1 | AuthUserFile /opt/scripta/etc/uipassword 2 | AuthType Basic 3 | AuthName "root" 4 | Require valid-user 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Updated Image: https://www.dropbox.com/s/v2qdzkj5qx0pkl0/ScriptaV042414.img.zip 2 | 3 | Added donation links 4 | 5 | Watchdog fix 6 | 7 | Graph fix coded into rc.local startup routine. This should be a permanent fix to graph issues 8 | 9 | Scripta- LTC address set as default mining pool 10 | 11 | Note: The Gridseed clock option is set by default at 875. This does produce slightly higher hardware errors, but in the long term the increased hashrate outperforms the subsequent HW errors, especially when mining lower dificulty coins. 12 | 13 | ------------------------------------------------------------------------ 14 | 4-22-14 15 | New Image Link: https://www.dropbox.com/s/28u6vtbo3m95fnx/ScriptaGridBeta042114.img.zip 16 | 17 | To get the graphs working login to Scripta and run the following command 18 | ``` 19 | sudo chown root:root /var/spool/cron/crontabs/root 20 | ``` 21 | Should fix any static graph issues still present. Update script still in progress, reboot and shutdown commands as well. 22 | 23 | ------------------------------------------------------------------------ 24 | 25 | This is a new version of Scripta using BFGMiner 3.99 to support both the Round Gridseed and stick USB DualMiners. This particular version was built using the original code and some of Mox235's changes. I will post a complete image file shortly. 26 | 27 | For both WebUI and root access the password is "scripta" (and user is root) 28 | For DualMiner/Gridseed make sure the following options are enabled on the miner settings page: 29 | ``` 30 | scan - dualminer:all or gridseed:all 31 | 32 | set-device - dualminer:clock=850 or gridseed:clock=850 33 | ``` 34 | 35 | If the device does not automatically recognize your miners, you can ssh root@"scripta IP address" and use command "screen -r" to manually add devices in BFG menu. 36 | 37 | Known Issues: 38 | - WebUI does not load if RPi is turned on with Miner's connected (to work-around this, plug in the RPi and wait until you see yellow and green activity LEDs, then wait 5-10 seconds before plugging in Miner) 39 | - Individual Miner Serial numbers don't show. Plan on adding support to set per-device clock speed by individual serial number. 40 | - Reboot and shutdown commands can be finicky. 41 | 42 | 43 | If you have found use for this version please consider a donation, as we opted out of building it into the program 44 | 45 | BTC: 199GzQnNAs9BBxXSmRxKECNQ1GPF2ZZ55j 46 | 47 | LTC: LVmN9MoAbn4hQSJZrzN65oiL7W4SAY9A2q 48 | 49 | ---== Scripta ==--- 50 | 51 | The turnkey solution for litecoin mining with raspberry pi and fpga/asic boards 52 | 53 | 54 | ---=== INSTALL INTRUCTIONS ===--- 55 | 56 | 57 | 58 | ---=== The easy way ===--- 59 | 60 | 1) Download the full image here http://www.lateralfactory.com/download.php?file=scripta-1_1.tgz 61 | 62 | 2) Burn it on a ssd in your favourite way 63 | 64 | 3) Log in as root from a console (pw is "scripta") 65 | 66 | 4) Remember to change root password with passwd 67 | 68 | 5) Enjoy 69 | 70 | 71 | 72 | ---=== The way of the turtle ===--- 73 | 74 | Start from a fresh raspbian wheezy (tested with 2014-01-07) Download here http://downloads.raspberrypi.org/raspbian_latest 75 | 76 | $>raspi-config ( if needed "Expand Filesystem" and reboot ) 77 | 78 | $>sudo apt-get update 79 | 80 | $>sudo apt-get install lighttpd 81 | 82 | $>sudo apt-get install php5-common php5-cgi php5 (Pay attention to packet's order) 83 | 84 | $>sudo lighty-enable-mod fastcgi-php 85 | 86 | $>sudo /etc/init.d/lighttpd force-reload 87 | 88 | ---= Add pi user to www-data group =--- 89 | 90 | $>sudousermod -a -G www-data pi 91 | 92 | $>sudo apt-get install php5-rrd libexpect-php5 php-auth-sasl php-mail php-net-smtp php-net-socket 93 | 94 | 95 | ---= Needed to enable https =--- 96 | 97 | $>sudo mkdir /etc/lighttpd/certs 98 | 99 | $>sudo su 100 | 101 | $>cd /etc/lighttpd/certs 102 | 103 | $>openssl req -new -x509 -keyout lighttpd.pem -out lighttpd.pem -days 365 -nodes 104 | 105 | $>chmod 400 lighttpd.pem 106 | 107 | $>/etc/init.d/lighttpd force-reload 108 | 109 | 110 | ---= edit /etc/lighttpd/lighttpd.conf =--- 111 | 112 | $>pico /etc/lighttpd/lighttpd.conf 113 | 114 | ---= add the following lines at the end =--- 115 | 116 | $SERVER["socket"] == ":443" { 117 | ssl.engine = "enable" 118 | ssl.pemfile = "/etc/lighttpd/certs/lighttpd.pem" 119 | } 120 | 121 | ---= libs for cgminer =--- 122 | 123 | $>sudo apt-get install libjansson4 libusb-1.0-0 ntpdate screen 124 | 125 | ---= install scripta package =--- 126 | 127 | $>cd / 128 | 129 | $>tar -xf scripta_1-1.tgz 130 | 131 | -------------------------------------------------------------------------------- /etc/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # rc.local 4 | # 5 | # This script is executed at the end of each multiuser runlevel. 6 | # Make sure that the script will "exit 0" on success or any other 7 | # value on error. 8 | # 9 | # In order to enable or disable this script just change the execution 10 | # bits. 11 | # 12 | # By default this script does nothing. 13 | 14 | # Print the IP address 15 | _IP=$(hostname -I) || true 16 | if [ "$_IP" ]; then 17 | 18 | echo " " 19 | echo " _________ .__ __ " 20 | echo " / _____/ ___________|__|______/ |______ " 21 | echo " \_____ \_/ ___\_ __ \ \____ \ __\__ \ " 22 | echo " / \ \___| | \/ | |_> > | / __ \_ " 23 | echo "/_______ /\___ >__| |__| __/|__| (____ / " 24 | echo " \/ \/ |__| \/ " 25 | 26 | printf "Connect to http://%s to manage Scripta.\n" "$_IP" 27 | printf "Happy mining!\n" 28 | 29 | sudo /opt/scripta/startup/miner-start.sh & 30 | sudo chown root:root /var/spool/cron/crontabs/root & 31 | 32 | fi 33 | 34 | exit 0 35 | -------------------------------------------------------------------------------- /opt/scripta/README.md: -------------------------------------------------------------------------------- 1 | Further informations on Scripta can be found at http://www.lateralfactory.com/scripta/ 2 | 3 | -------------------------------------------------------------------------------- /opt/scripta/bin/bfgminer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/bin/bfgminer -------------------------------------------------------------------------------- /opt/scripta/bin/bfgminer-rpc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/bin/bfgminer-rpc -------------------------------------------------------------------------------- /opt/scripta/bin/cgminer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/bin/cgminer -------------------------------------------------------------------------------- /opt/scripta/bin/cgminer-gc3355: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/bin/cgminer-gc3355 -------------------------------------------------------------------------------- /opt/scripta/bin/cgminer-monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Romain Dura | romain@shazbits.com 3 | # https://github.com/shazbits/cgminer-monitor 4 | # BTC 1Kcn1Hs76pbnBpBQHwdsDmr3CZYcoCAwjj 5 | # 6 | 7 | import socket 8 | import sys 9 | import time 10 | import smtplib 11 | import json 12 | import os 13 | import threading 14 | import SimpleHTTPServer 15 | import SocketServer 16 | import urllib2 17 | 18 | 19 | # 20 | # Config 21 | # 22 | 23 | bfgminer_host = 'localhost' 24 | bfgminer_port = 4028 25 | email_smtp_server = 'smtp.gmail.com:587' 26 | email_login = 'mylogin' 27 | email_password = 'mypassword' 28 | email_from = 'myemail@example.com' 29 | email_to = 'myemail@example.com' 30 | email_subject = 'Miner warning detected' 31 | monitor_interval = 15 32 | monitor_wait_after_email = 60 33 | monitor_http_interface = '0.0.0.0' 34 | monitor_http_port = 84 35 | monitor_restart_bfgminer_if_sick = True 36 | monitor_send_email_alerts = True 37 | monitor_max_temperature = 85 38 | monitor_min_mhs_scrypt = 0.5 39 | monitor_min_mhs_sha256 = 500 40 | monitor_enable_pools = False 41 | 42 | # MMCFE pools (www.wemineltc.com, dgc.mining-foreman.org, megacoin.miningpool.co, etc.) 43 | # Replace the URLs and/or API keys by your own, add as many pools as you like 44 | pools = [ 45 | { 46 | 'url': 'http://www.digicoinpool.com/api?api_key=1234567890', 47 | 'cur': 'DGC' 48 | }, 49 | { 50 | 'url': 'http://www.wemineltc.com/api?api_key=1234567890', 51 | 'cur': 'LTC' 52 | }, 53 | ] 54 | 55 | 56 | # 57 | # Shared between monitor and http server 58 | # 59 | 60 | shared_output = '' 61 | shared_output_lock = threading.Lock() 62 | 63 | 64 | # 65 | # cgminer RPC 66 | # 67 | 68 | class BfgminerClient: 69 | def __init__(self, host, port): 70 | self.host = host 71 | self.port = port 72 | 73 | def command(self, command, parameter): 74 | # sockets are one time use. open one for each command 75 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 76 | 77 | try: 78 | sock.connect((self.host, self.port)) 79 | if parameter: 80 | self._send(sock, json.dumps({"command": command, "parameter": parameter})) 81 | else: 82 | self._send(sock, json.dumps({"command": command})) 83 | received = self._receive(sock) 84 | except Exception as e: 85 | print e 86 | sock.close() 87 | return None 88 | 89 | sock.shutdown(socket.SHUT_RDWR) 90 | sock.close() 91 | 92 | # the null byte makes json decoding unhappy 93 | try: 94 | decoded = json.loads(received.replace('\x00', '')) 95 | return decoded 96 | except: 97 | pass # restart makes it fail, but it's ok 98 | 99 | def _send(self, sock, msg): 100 | totalsent = 0 101 | while totalsent < len(msg): 102 | sent = sock.send(msg[totalsent:]) 103 | if sent == 0: 104 | raise RuntimeError("socket connection broken") 105 | totalsent = totalsent + sent 106 | 107 | def _receive(self, sock, size=65500): 108 | msg = '' 109 | while True: 110 | chunk = sock.recv(size) 111 | if chunk == '': 112 | # end of message 113 | break 114 | msg = msg + chunk 115 | return msg 116 | 117 | 118 | # 119 | # Utils 120 | # 121 | 122 | def SendEmail(from_addr, to_addr_list, cc_addr_list, 123 | subject, message, login, password, 124 | smtpserver=email_smtp_server): 125 | header = 'From: %s\n' % from_addr 126 | header += 'To: %s\n' % ','.join(to_addr_list) 127 | header += 'Cc: %s\n' % ','.join(cc_addr_list) 128 | header += 'Subject: %s\n\n' % subject 129 | 130 | server = smtplib.SMTP(smtpserver) 131 | server.starttls() 132 | server.login(login, password) 133 | server.sendmail(from_addr, to_addr_list, header + message) 134 | server.quit() 135 | 136 | 137 | # 138 | # Monitor 139 | # 140 | 141 | def StartMonitor(client): 142 | os.system('cls') 143 | while (True): 144 | output = '' 145 | 146 | must_send_email = False 147 | must_restart = False 148 | 149 | result = client.command('coin', None) 150 | coin = '' 151 | if result: 152 | coin = result['COIN'][0]['Hash Method'] 153 | output = 'Coin : %s\n' % coin 154 | 155 | result = client.command('pools', None) 156 | if result: 157 | output += 'Pool URL : %s\n' % (result['POOLS'][0]['Stratum URL']) 158 | warning = ' <----- /!\\' if result['POOLS'][0]['Status'] != 'Alive' else '' 159 | must_send_email = True if warning != '' else must_send_email 160 | output += 'Pool : %s%s\n' % (result['POOLS'][0]['Status'], warning) 161 | 162 | # Put this in a loop for multi-gpu support 163 | result = client.command('gpu', '0') 164 | if result: 165 | gpu_result = result['GPU'][0] 166 | warning = ' <----- /!\\' if gpu_result['Status'] != 'Alive' else '' 167 | must_restart = True if warning != '' else False 168 | must_send_email = True if warning != '' else must_send_email 169 | output += 'GPU 0 : %s%s\n' % (gpu_result['Status'], warning) 170 | 171 | min_mhs = monitor_min_mhs_scrypt if coin == 'scrypt' else monitor_min_mhs_sha256 172 | warning = ' <----- /!\\' if gpu_result['MHS 1s'] < min_mhs else '' 173 | must_send_email = True if warning != '' else must_send_email 174 | output += 'MHS 1s/av: %s/%s%s\n' % (gpu_result['MHS 1s'], gpu_result['MHS av'], warning) 175 | 176 | warning = ' <----- /!\\' if gpu_result['Temperature'] > monitor_max_temperature else '' 177 | must_send_email = True if warning != '' else must_send_email 178 | output += 'Temp : %s%s\n' % (gpu_result['Temperature'], warning) 179 | output += 'Intensity: %s\n' % gpu_result['Intensity'] 180 | 181 | result = client.command('summary', None) 182 | if result: 183 | if result['SUMMARY'][0]['Hardware Errors'] > 0: 184 | must_send_email = True 185 | output += 'HW err : %s%s\n' % (result['SUMMARY'][0]['Hardware Errors'], ' <----- /!\\') 186 | 187 | result = client.command('stats', None) 188 | if result: 189 | uptime = result['STATS'][0]['Elapsed'] 190 | output += 'Uptime : %02d:%02d:%02d\n' % (uptime / 3600, (uptime / 60) % 60, uptime % 60) 191 | print output 192 | 193 | global shared_output 194 | global shared_output_lock 195 | shared_output_lock.acquire() 196 | shared_output = output 197 | shared_output_lock.release() 198 | 199 | if must_restart and monitor_restart_bfgminer_if_sick: 200 | print 'Restarting' 201 | result = client.command('restart', None) 202 | 203 | if must_send_email and monitor_send_email_alerts and uptime > 10: 204 | SendEmail(from_addr=email_from, to_addr_list=[email_to], cc_addr_list=[], 205 | subject=email_subject, 206 | message=output, 207 | login=email_login, 208 | password=email_password) 209 | time.sleep(monitor_wait_after_email) 210 | 211 | # Sleep by increments of 1 second to catch the keyboard interrupt 212 | for i in range(monitor_interval): 213 | time.sleep(1) 214 | 215 | os.system('cls') 216 | 217 | 218 | # 219 | # HTTP server request handler 220 | # 221 | 222 | class BFMinerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 223 | def do_GET(self): 224 | self.send_response(200) 225 | 226 | if self.path == '/favicon.ico': 227 | return 228 | 229 | self.send_header("Content-type", "text/html") 230 | self.end_headers() 231 | 232 | global shared_output 233 | global shared_output_lock 234 | shared_output_lock.acquire() 235 | html_output = shared_output[:-1] # one too many \n 236 | shared_output_lock.release() 237 | 238 | # Get balance from pools 239 | pools_output = '' 240 | if monitor_enable_pools: 241 | td_div = '' 242 | for pool in pools: 243 | try: 244 | response = urllib2.urlopen(pool['url']) 245 | data = json.load(response) 246 | pools_output += '\n\n' + td_div + '\n' + 'pool' + '' + td_div + pool['cur'] + ' %.6f' % (float(data['confirmed_rewards'])) 247 | except urllib2.HTTPError as e: 248 | pools_output += '\n\n' + td_div + '\n' + 'pool' + '' + td_div + pool['cur'] + ' Error: ' + str(e.code) 249 | except urllib2.URLError as e: 250 | pools_output += '\n\n' + td_div + '\n' + 'pool' + '' + td_div + pool['cur'] + ' Error: ' + e.reason 251 | except: 252 | pools_output += '\n\n' + td_div + '\n' + 'pool' + '' + td_div + pool['cur'] + ' Error: unsupported pool?' 253 | 254 | # Format results from the monitor 255 | td_div = '' 256 | html_output = ('\n\n' + td_div + '\n').join(html_output.replace(': ', '' + td_div).split('\n')) 257 | html_output += pools_output 258 | html = """ 259 | 260 | 261 | 262 | bfgminer monitor 263 | 264 | 265 | 266 | 269 |
267 | """ + html_output + """ 268 |
270 | 271 | 272 | """ 273 | self.wfile.write(html) 274 | 275 | 276 | # 277 | # usage: cgminer-monitor.py [command] [parameter] 278 | # No arguments: monitor + http server mode. Press CTRL+C to stop. 279 | # Arguments: send the command with optional parameter and exit. 280 | # 281 | 282 | if __name__ == "__main__": 283 | command = sys.argv[1] if len(sys.argv) > 1 else None 284 | parameter = sys.argv[2] if len(sys.argv) > 2 else None 285 | 286 | client = BFgminerClient(bfgminer_host, bfgminer_port) 287 | 288 | if command: 289 | # An argument was specified, ask cgminer and exit 290 | result = client.command(command, parameter) 291 | print result if result else 'Cannot get valid response from bfgminer' 292 | else: 293 | # No argument, start the monitor and the http server 294 | try: 295 | server = SocketServer.TCPServer((monitor_http_interface, monitor_http_port), BFGMinerRequestHandler) 296 | threading.Thread(target=server.serve_forever).start() 297 | StartMonitor(client) 298 | except KeyboardInterrupt: 299 | server.shutdown() 300 | 301 | -------------------------------------------------------------------------------- /opt/scripta/bin/cgminer_x8_lite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/bin/cgminer_x8_lite -------------------------------------------------------------------------------- /opt/scripta/bin/wdog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Scripta watchdog test for cgminer status 4 | # 5 | # parts used from cgminer-monitor.py 6 | # Romain Dura | romain@shazbits.com 7 | # https://github.com/shazbits/cgminer-monitor 8 | # BTC 1Kcn1Hs76pbnBpBQHwdsDmr3CZYcoCAwjj 9 | # 10 | 11 | import socket 12 | import sys 13 | import time 14 | import smtplib 15 | import json 16 | import os 17 | import threading 18 | import SimpleHTTPServer 19 | import SocketServer 20 | import urllib2 21 | import datetime, time 22 | import pprint 23 | 24 | # 25 | # Config 26 | # 27 | 28 | cgminer_host = 'localhost' 29 | cgminer_port = 4028 30 | monitor_interval = 15 31 | monitor_wait_after_email = 10 32 | 33 | shared_output = '' 34 | shared_output_lock = threading.Lock() 35 | 36 | # 37 | # cgminer RPC 38 | # 39 | 40 | class CgminerClient: 41 | def __init__(self, host, port): 42 | self.host = host 43 | self.port = port 44 | 45 | def command(self, command, parameter): 46 | # sockets are one time use. open one for each command 47 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 48 | 49 | try: 50 | sock.connect((self.host, self.port)) 51 | if parameter: 52 | self._send(sock, json.dumps({"command": command, "parameter": parameter})) 53 | else: 54 | self._send(sock, json.dumps({"command": command})) 55 | received = self._receive(sock) 56 | except Exception as e: 57 | print e 58 | sock.close() 59 | return None 60 | 61 | sock.shutdown(socket.SHUT_RDWR) 62 | sock.close() 63 | 64 | # the null byte makes json decoding unhappy 65 | try: 66 | decoded = json.loads(received.replace('\x00', '')) 67 | return decoded 68 | except: 69 | pass # restart makes it fail, but it's ok 70 | 71 | def _send(self, sock, msg): 72 | totalsent = 0 73 | while totalsent < len(msg): 74 | sent = sock.send(msg[totalsent:]) 75 | if sent == 0: 76 | raise RuntimeError("socket connection broken") 77 | totalsent = totalsent + sent 78 | 79 | def _receive(self, sock, size=65500): 80 | msg = '' 81 | while True: 82 | chunk = sock.recv(size) 83 | if chunk == '': 84 | # end of message 85 | break 86 | msg = msg + chunk 87 | return msg 88 | 89 | 90 | # 91 | # Utils 92 | # 93 | 94 | def SendEmail(from_addr, to_addr_list, cc_addr_list, 95 | subject, message, login, password, 96 | smtpserver): 97 | header = 'From: %s\n' % from_addr 98 | header += 'To: %s\n' % ','.join(to_addr_list) 99 | header += 'Cc: %s\n' % ','.join(cc_addr_list) 100 | header += 'Subject: %s\n\n' % subject 101 | 102 | server = smtplib.SMTP(smtpserver) 103 | server.starttls() 104 | server.login(login, password) 105 | server.sendmail(from_addr, to_addr_list, header + message) 106 | server.quit() 107 | print 'send email: ' + to_addr_list[0] 108 | 109 | 110 | if __name__ == "__main__": 111 | 112 | now = (datetime.datetime.now()-datetime.datetime(1970,1,1)).total_seconds() 113 | 114 | if os.path.exists('/tmp/wdog.ts'): 115 | ts_file=open('/tmp/wdog.ts','r') 116 | dt = now - float(ts_file.readline()) 117 | ts_file.close(); 118 | else: 119 | ts_file=open('/tmp/wdog.ts','w') 120 | ts_file.write(str(now)); 121 | ts_file.close; 122 | dt = 0.0; 123 | 124 | if os.path.exists('/tmp/reboot.ts'): 125 | print 'OK - wait for reboot command' 126 | sys.exit(0) 127 | 128 | conf_file=open('/opt/scripta/etc/scripta.conf') 129 | conf = json.load(conf_file) 130 | pprint.pprint(conf) 131 | conf_file.close() 132 | 133 | if conf['rebootEnable']: 134 | conf['rebootEnable'] = False 135 | with open('/opt/scripta/etc/scripta.conf', 'w') as outfile: 136 | json.dump(conf, outfile) 137 | print 'OK - reboot command' 138 | sys.exit(1) 139 | 140 | if not conf['recoverEnable']: 141 | print 'OK - scripta watchdog disabled' 142 | sys.exit(0) 143 | 144 | if dt < 60.0: 145 | print 'OK - wait for cgminer startup ' + str(dt) + ' sec' 146 | sys.exit(0) 147 | 148 | print 'expected device count: ' + str(conf['miningExpDev']) 149 | print 'expected min hashrate: ' + str(conf['miningExpHash']) 150 | 151 | pid_file=open('/opt/scripta/var/bfgminer.pid','r') 152 | if not pid_file: 153 | print 'ERROR - bfgminer.pid not found' 154 | else: 155 | pid = int(pid_file.readline()) 156 | pid_file.close() 157 | ps = '/proc/' + str(pid) + '/' 158 | if os.path.exists(ps): 159 | print 'OK - bfgminer process running' 160 | else: 161 | output = 'ERROR - bfgminer process not running (pid ' + ps + ')' 162 | time.sleep(3) 163 | if not os.path.exists(ps): 164 | output = 'ERROR - bfgminer process not running (pid ' + ps + ')' 165 | if conf['alertEnable']: 166 | SendEmail( 167 | from_addr='scripta@hotmail.com', 168 | to_addr_list=[conf['alertEmailTo']], 169 | cc_addr_list=[], 170 | subject='Scripta Reboot [' + conf['alertDevice'] + ']', 171 | message=output, 172 | login=conf['alertSmtpUser'], 173 | password=conf['alertSmtpPwd'], 174 | smtpserver=conf['alertSmtp'] + ':' + str(conf['alertSmtpPort'])) 175 | time.sleep(monitor_wait_after_email) 176 | ts_file=open('/tmp/reboot.ts','w') 177 | ts_file.write(str(now)); 178 | ts_file.close; 179 | sys.exit(1) # reboot 180 | 181 | client = CgminerClient(cgminer_host, cgminer_port) 182 | 183 | result = client.command('pgacount', None) 184 | if result: 185 | dev = result['PGAS'][0]['Count'] 186 | if conf['miningExpDev'] > dev: 187 | output = 'ERROR - device count: ' + str(dev) + '\n\n' + pprint.pformat(result) 188 | print output 189 | if conf['alertEnable']: 190 | SendEmail( 191 | from_addr='scripta@hotmail.com', 192 | to_addr_list=[conf['alertEmailTo']], 193 | cc_addr_list=[], 194 | subject='Scripta Reboot [' + conf['alertDevice'] + ']', 195 | message=output, 196 | login=conf['alertSmtpUser'], 197 | password=conf['alertSmtpPwd'], 198 | smtpserver=conf['alertSmtp'] + ':' + str(conf['alertSmtpPort'])) 199 | time.sleep(monitor_wait_after_email) 200 | ts_file=open('/tmp/reboot.ts','w') 201 | ts_file.write(str(now)); 202 | ts_file.close; 203 | sys.exit(1) # reboot 204 | else: 205 | print 'OK - device count: ' + str(dev) 206 | else: 207 | print 'OK - cgminer not ready' 208 | sys.exit(0); 209 | 210 | result = client.command('devs', None) 211 | if result: 212 | for d in result['DEVS']: 213 | if conf['miningExpHash'] > d['MHS rolling']: 214 | output = 'ERROR - ' + str(d['Name']) + str(d['ID']) + ' hashrate: ' + str(d['MHS rolling']) + '\n\n' + pprint.pformat(result) 215 | print output 216 | if conf['alertEnable']: 217 | SendEmail( 218 | from_addr='scripta@hotmail.com', 219 | to_addr_list=[conf['alertEmailTo']], 220 | cc_addr_list=[], 221 | subject='Scripta Reboot [' + conf['alertDevice'] + ']', 222 | message=output, 223 | login=conf['alertSmtpUser'], 224 | password=conf['alertSmtpPwd'], 225 | smtpserver=conf['alertSmtp'] + ':' + str(conf['alertSmtpPort'])) 226 | time.sleep(monitor_wait_after_email) 227 | ts_file=open('/tmp/reboot.ts','w') 228 | ts_file.write(str(now)); 229 | ts_file.close; 230 | sys.exit(1) # reboot 231 | else: 232 | print 'OK - ' + str(d['ID']) + ' hashrate: ' + str(d['MHS rolling']) 233 | 234 | sys.exit(0) 235 | -------------------------------------------------------------------------------- /opt/scripta/etc/bfgminer.conf: -------------------------------------------------------------------------------- 1 | { 2 | "scrypt" : true, 3 | "api-listen": true, 4 | "api-port": "4028", 5 | "expiry": "120", 6 | "hotplug": "5", 7 | "log": "5", 8 | "no-pool-disable": true, 9 | "queue": "1", 10 | "scan-time": "60", 11 | "shares": "0", 12 | "kernel-path" : "/usr/local/bin", 13 | "api-allow": "W:127.0.0.1,W192.168.1/0", 14 | "scan" : "gridseed:all", 15 | "set-device" : "gridseed:clock=850", 16 | "pools": [ 17 | { 18 | "url" : "stratum+tcp://multi.ghash.io:3333", 19 | "user" : "richmondimage.gridseed2", 20 | "pass" : "x", 21 | "pool-priority" : "0" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /opt/scripta/etc/cron.d/5min/ALERTdeviceCount: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | $devcount and $settings['donateActive'] == 0) { 30 | if ($settings['miningExpDev'] <> $devcount ) { 31 | 32 | // Send an email if the devices dont match and set the deviceWarn falt 33 | 34 | $message = "Scripta notification: " . $settings['alertDevice'] . ": Unexpected device count " . $devcount . " (Expected " . $settings['miningExpDev'] . ")"; 35 | 36 | sendEmail($settings, $message, $message); 37 | 38 | // Set the warning flag 39 | 40 | $settings['devicesWarn'] = 1; 41 | writeSettings($settings); 42 | 43 | 44 | } 45 | 46 | if($settings['devicesWarn'] == 1 and $settings['miningExpDev'] == $devcount) { 47 | 48 | $message = "Scripta notification: " . $settings['alertDevice'] . ": Unexpected device count recovered"; 49 | 50 | sendEmail($settings, $message, $message); 51 | 52 | // Clear the warning flag 53 | $settings['devicesWarn'] = 0; 54 | writeSettings($settings); 55 | 56 | } 57 | 58 | } 59 | var_dump($settings); 60 | 61 | function deviceCount($devs) { 62 | 63 | $devices = 0; 64 | 65 | foreach ($devs as $dev) { 66 | if ($dev['MHS5s'] > 0) { 67 | $devices++; 68 | } 69 | } 70 | 71 | return $devices; 72 | 73 | } 74 | -------------------------------------------------------------------------------- /opt/scripta/etc/cron.d/5min/ALERThashrate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | $hashrate and $settings['donateActive'] == 0) { 16 | 17 | // Send an email if the devices dont match and set the deviceWarn falt 18 | 19 | 20 | $warning = "Scripta notification: " . $settings['alertDevice'] . ": Unexpected hashrate " . $hashrate . " MH/s (Expected " . $settings['miningExpHash'] . " MH/s)"; 21 | 22 | sendEmail($settings, $warning, $warning); 23 | 24 | 25 | // Set the warning flag 26 | 27 | $settings['hashWarn'] = 1; 28 | writeSettings($settings); 29 | echo " fault"; 30 | 31 | } 32 | 33 | if($settings['hashWarn'] == 1 and $settings['miningExpHash'] < $hashrate) { 34 | 35 | $warning = "Scripta notification: " . $settings['alertDevice'] . ": Unexpected hashrate recovered"; 36 | 37 | sendEmail($settings, $warning, $warning); 38 | 39 | // Clear the warning flag 40 | $settings['hashWarn'] = 0; 41 | writeSettings($settings); 42 | echo " nofault"; 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /opt/scripta/etc/cron.d/5min/hashrate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | -------------------------------------------------------------------------------- /opt/scripta/etc/cron.d/5min/inc: -------------------------------------------------------------------------------- 1 | /var/www/inc -------------------------------------------------------------------------------- /opt/scripta/etc/cron.d/5min/temp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | 47 | -------------------------------------------------------------------------------- /opt/scripta/etc/cron.d/hourly/donate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | 0){ 17 | 18 | if (date('H') == 12) { 19 | $miner = "/opt/scripta/etc/miner.conf"; 20 | $donate = "/opt/scripta/etc/miner.conf.donate"; 21 | $original = "/opt/scripta/etc/miner.conf.orig"; 22 | 23 | // Take your miner info and backup 24 | copy($miner, $original); 25 | 26 | // Sleep for 60 secconds to avoid monitor scripts 27 | sleep(30); 28 | 29 | $settings['donateActive'] = 1; 30 | writeSettings($settings); 31 | 32 | // Restart using donation pools 33 | copy($donate, $miner); 34 | 35 | exec("/usr/bin/killall cgminer"); 36 | exec("/usr/bin/killall bfgminer"); 37 | 38 | sleep(5); 39 | 40 | // Copy back the normal pools 41 | 42 | copy($original, $miner); 43 | 44 | // Switch back to your pools after x minutes 45 | sleep($settings['donateAmount'] * 60); 46 | 47 | $settings['donateActive'] = 0; 48 | writeSettings($settings); 49 | 50 | exec("/usr/bin/killall cgminer"); 51 | exec("/usr/bin/killall bfgminer"); 52 | 53 | echo "Finish !"; 54 | } 55 | } 56 | 57 | 58 | 59 | // stratum.btcguild.com:3333 MinePeon_Donate MinePeon_Donate 60 | // pool.50btc.com:8332 Donate 61 | -------------------------------------------------------------------------------- /opt/scripta/etc/miner.conf: -------------------------------------------------------------------------------- 1 | { 2 | "api-listen": true, 3 | "api-port": "4028", 4 | "expiry": "120", 5 | "hotplug": "5", 6 | "log": "5", 7 | "no-pool-disable": true, 8 | "queue": "1", 9 | "scan-time": "30", 10 | "scrypt": true, 11 | "shares": "0", 12 | "scan": "dualminer:all", 13 | "set-device": "dualminer:clock=850", 14 | "api-allow": "W:127.0.0.1,W:192.168.1/24", 15 | "pools": [ 16 | { 17 | "url": "stratum+tcp://multi.ghash.io:3333", 18 | "user": "richmondimage.dual", 19 | "pass": "x", 20 | "prio": "0" 21 | }, 22 | { 23 | "url": "stratum+tcp://ltc.ghash.io:3333", 24 | "user": "richmondimage.scripta", 25 | "pass": "x", 26 | "prio": "1" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /opt/scripta/etc/miner.options.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "api-listen", 4 | "value": true 5 | }, 6 | { 7 | "key": "api-port", 8 | "value": "4028" 9 | }, 10 | { 11 | "key": "expiry", 12 | "value": "120" 13 | }, 14 | { 15 | "key": "hotplug", 16 | "value": "5" 17 | }, 18 | { 19 | "key": "log", 20 | "value": "5" 21 | }, 22 | { 23 | "key": "no-pool-disable", 24 | "value": true 25 | }, 26 | { 27 | "key": "queue", 28 | "value": "1" 29 | }, 30 | { 31 | "key": "scan-time", 32 | "value": "30" 33 | }, 34 | { 35 | "key": "scrypt", 36 | "value": true 37 | }, 38 | { 39 | "key": "shares", 40 | "value": "0" 41 | }, 42 | { 43 | "key": "scan", 44 | "value": "dualminer:all" 45 | }, 46 | { 47 | "key": "set-device", 48 | "value": "dualminer:clock=850" 49 | }, 50 | { 51 | "key": "api-allow", 52 | "value": "W:127.0.0.1,W:192.168.1/24" 53 | } 54 | ] -------------------------------------------------------------------------------- /opt/scripta/etc/miner.pools.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "stratum+tcp://multi.ghash.io:3333", 4 | "user": "richmondimage.dual", 5 | "pass": "x", 6 | "prio": "0" 7 | }, 8 | { 9 | "url": "stratum+tcp://ltc.ghash.io:3333", 10 | "user": "richmondimage.scripta", 11 | "pass": "x", 12 | "prio": "1" 13 | } 14 | ] -------------------------------------------------------------------------------- /opt/scripta/etc/scripta.conf: -------------------------------------------------------------------------------- 1 | { 2 | "userHelp": false, 3 | "userTimezone": "America/New_York", 4 | "date": "2014-04-12 00:18:57", 5 | "remoteEnable": false, 6 | "recoverEnable": true, 7 | "alertEnable": false, 8 | "donateEnable": false, 9 | "alertDevice": "", 10 | "alertEmail": "", 11 | "alertSmtp": "", 12 | "alertSmtpUser": "", 13 | "alertSmtpPwd": "", 14 | "miningExpDev": 6, 15 | "liveMax": 100, 16 | "devicesWarn": 0, 17 | "alertSmtpPort": 587, 18 | "miningExpHash": 300, 19 | "hashWarn": 1 20 | } -------------------------------------------------------------------------------- /opt/scripta/etc/uipasswd: -------------------------------------------------------------------------------- 1 | scripta:9a4f049c0f8e3b60ddf7ddf0d01a9d0e -------------------------------------------------------------------------------- /opt/scripta/etc/version: -------------------------------------------------------------------------------- 1 | 1.0 2 | -------------------------------------------------------------------------------- /opt/scripta/http/rrd/mhsav-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/http/rrd/mhsav-day.png -------------------------------------------------------------------------------- /opt/scripta/http/rrd/mhsav-hour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/http/rrd/mhsav-hour.png -------------------------------------------------------------------------------- /opt/scripta/http/rrd/mhsav-month.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/http/rrd/mhsav-month.png -------------------------------------------------------------------------------- /opt/scripta/http/rrd/mhsav-week.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/http/rrd/mhsav-week.png -------------------------------------------------------------------------------- /opt/scripta/http/rrd/mhsav-year.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/http/rrd/mhsav-year.png -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker-0.1.la: -------------------------------------------------------------------------------- 1 | # libblkmaker-0.1.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.2 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libblkmaker-0.1.so.0' 9 | 10 | # Names of this library. 11 | library_names='libblkmaker-0.1.so.0.4.1 libblkmaker-0.1.so.0 libblkmaker-0.1.so' 12 | 13 | # The name of the static archive. 14 | old_library='' 15 | 16 | # Linker flags that can not go in dependency_libs. 17 | inherited_linker_flags='' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs='' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libblkmaker-0.1. 26 | current=4 27 | age=4 28 | revision=1 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=no 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/opt/minepeon/lib' 42 | -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker-0.1.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker-0.1.so -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker-0.1.so.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker-0.1.so.0 -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker-0.1.so.0.3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker-0.1.so.0.3.1 -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker-0.1.so.0.4.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker-0.1.so.0.4.0 -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker-0.1.so.0.4.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker-0.1.so.0.4.1 -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker_jansson-0.1.la: -------------------------------------------------------------------------------- 1 | # libblkmaker_jansson-0.1.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.2 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libblkmaker_jansson-0.1.so.0' 9 | 10 | # Names of this library. 11 | library_names='libblkmaker_jansson-0.1.so.0.4.1 libblkmaker_jansson-0.1.so.0 libblkmaker_jansson-0.1.so' 12 | 13 | # The name of the static archive. 14 | old_library='' 15 | 16 | # Linker flags that can not go in dependency_libs. 17 | inherited_linker_flags='' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' -L.libs /opt/minepeon/lib/libblkmaker-0.1.la -ljansson' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libblkmaker_jansson-0.1. 26 | current=4 27 | age=4 28 | revision=1 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=no 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/opt/minepeon/lib' 42 | -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker_jansson-0.1.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker_jansson-0.1.so -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker_jansson-0.1.so.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker_jansson-0.1.so.0 -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker_jansson-0.1.so.0.3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker_jansson-0.1.so.0.3.1 -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker_jansson-0.1.so.0.4.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker_jansson-0.1.so.0.4.0 -------------------------------------------------------------------------------- /opt/scripta/lib/libblkmaker_jansson-0.1.so.0.4.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libblkmaker_jansson-0.1.so.0.4.1 -------------------------------------------------------------------------------- /opt/scripta/lib/libusb-1.0.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libusb-1.0.a -------------------------------------------------------------------------------- /opt/scripta/lib/libusb-1.0.la: -------------------------------------------------------------------------------- 1 | # libusb-1.0.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.2 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libusb-1.0.so.2' 9 | 10 | # Names of this library. 11 | library_names='libusb-1.0.so.2.0.0 libusb-1.0.so.2 libusb-1.0.so' 12 | 13 | # The name of the static archive. 14 | old_library='libusb-1.0.a' 15 | 16 | # Linker flags that can not go in dependency_libs. 17 | inherited_linker_flags=' -pthread' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' -ludev' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libusb-1.0. 26 | current=2 27 | age=0 28 | revision=0 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=no 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/opt/minepeon/lib' 42 | -------------------------------------------------------------------------------- /opt/scripta/lib/libusb-1.0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libusb-1.0.so -------------------------------------------------------------------------------- /opt/scripta/lib/libusb-1.0.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libusb-1.0.so.2 -------------------------------------------------------------------------------- /opt/scripta/lib/libusb-1.0.so.2.0.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/lib/libusb-1.0.so.2.0.0 -------------------------------------------------------------------------------- /opt/scripta/lib/pkgconfig/libblkmaker_jansson-0.1.pc: -------------------------------------------------------------------------------- 1 | prefix=/opt/minepeon 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: libblkmaker_jansson 7 | Description: Bitcoin block maker library. 8 | Version: 0.1 9 | URL: http://gitorious.org/bitcoin/libblkmaker 10 | Libs: -L${libdir} -lblkmaker-0.1 -lblkmaker_jansson-0.1 11 | Cflags: -I${includedir}/libblkmaker-0.1 12 | -------------------------------------------------------------------------------- /opt/scripta/lib/pkgconfig/libusb-1.0.pc: -------------------------------------------------------------------------------- 1 | prefix=/opt/minepeon 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: libusb-1.0 7 | Description: C API for USB device access from Linux, Mac OS X, OpenBSD, NetBSD and Windows userspace 8 | Version: 1.0.16-rc10 9 | Libs: -L${libdir} -lusb-1.0 10 | Libs.private: -ludev -pthread 11 | Cflags: -I${includedir}/libusb-1.0 12 | 13 | -------------------------------------------------------------------------------- /opt/scripta/modules/PiMiner/PiMiner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys, subprocess, time, urllib2, socket 4 | sys.path.append("/home/pi/Adafruit-Raspberry-Pi-Python-Code/Adafruit_CharLCDPlate") 5 | from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate 6 | from PiMinerDisplay import PiMinerDisplay 7 | 8 | HOLD_TIME = 3.0 #Time (seconds) to hold select button for shut down 9 | REFRESH_TIME= 3.0 #Time (seconds) between data updates 10 | HALT_ON_EXIT= True 11 | display = PiMinerDisplay() 12 | lcd = display.lcd 13 | prevCol = -1 14 | prev = -1 15 | lastTime = time.time() 16 | 17 | def shutdown(): 18 | lcd.clear() 19 | if HALT_ON_EXIT: 20 | lcd.message('Wait 30 seconds\nto unplug...') 21 | subprocess.call("sync") 22 | subprocess.call(["shutdown", "-h", "now"]) 23 | else: 24 | exit(0) 25 | 26 | ''' 27 | #WIP - startup on boot 28 | def internetOn(): 29 | try: 30 | response=urllib2.urlopen('http://google.com',timeout=3) 31 | return True 32 | except urllib2.URLError as err: 33 | pass 34 | return False 35 | ''' 36 | 37 | #Check for network connection at startup 38 | t = time.time() 39 | while True: 40 | lcd.clear() 41 | lcd.message('checking network\nconnection ...') 42 | if (time.time() - t) > 120: 43 | # No connection reached after 2 minutes 44 | lcd.clear() 45 | lcd.message('network is\nunavailable') 46 | time.sleep(30) 47 | exit(0) 48 | try: 49 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 50 | s.connect(('8.8.8.8', 0)) 51 | lcd.backlight(lcd.ON) 52 | lcd.clear() 53 | lcd.message('IP address:\n' + s.getsockname()[0]) 54 | time.sleep(5) 55 | display.initInfo() # Start info gathering/display 56 | break # Success 57 | except: 58 | time.sleep(1) # Pause a moment, keep trying 59 | ''' 60 | if internetOn() == True: 61 | time.sleep(5) 62 | break # Success 63 | else: 64 | time.sleep(1) # Pause a moment, keep trying 65 | ''' 66 | 67 | # Listen for button presses 68 | while True: 69 | b = lcd.buttons() 70 | if b is not prev: 71 | if lcd.buttonPressed(lcd.SELECT): 72 | tt = time.time() # Start time of button press 73 | while lcd.buttonPressed(lcd.SELECT): # Wait for button release 74 | if (time.time() - tt) >= HOLD_TIME: # Extended hold? 75 | shutdown() # We're outta here 76 | display.backlightStep() 77 | elif lcd.buttonPressed(lcd.LEFT): 78 | display.scrollRight() 79 | elif lcd.buttonPressed(lcd.RIGHT): 80 | display.scrollLeft() 81 | elif lcd.buttonPressed(lcd.UP): 82 | display.modeUp() 83 | elif lcd.buttonPressed(lcd.DOWN): 84 | display.modeDown() 85 | prev = b 86 | lastTime = time.time() 87 | else: 88 | now = time.time() 89 | since = now - lastTime 90 | if since > REFRESH_TIME or since < 0.0: 91 | display.update() 92 | lastTime = now 93 | -------------------------------------------------------------------------------- /opt/scripta/modules/PiMiner/PiMinerDisplay.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from PiMinerInfo import PiMinerInfo 4 | from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate 5 | 6 | class PiMinerDisplay: 7 | 8 | col = [] 9 | prevCol = 0 10 | lcd = Adafruit_CharLCDPlate() 11 | info = None 12 | mode = 1 13 | offset = 0 14 | maxOffset = 0 15 | screen = [] 16 | 17 | def __init__(self): 18 | self.lcd.clear() 19 | self.col = (self.lcd.ON, self.lcd.OFF, self.lcd.YELLOW, self.lcd.OFF, 20 | self.lcd.GREEN, self.lcd.OFF, self.lcd.TEAL, self.lcd.OFF, 21 | self.lcd.BLUE, self.lcd.OFF, self.lcd.VIOLET, self.lcd.OFF, 22 | self.lcd.RED, self.lcd.OFF) 23 | self.lcd.backlight(self.col[self.prevCol]) 24 | 25 | #Show initial info (call after network connected) 26 | def initInfo(self): 27 | self.info = PiMinerInfo() 28 | self.dispLocalInfo() 29 | 30 | #Display Local Info - Accepted, Rejected, HW Errors \n Average Hashrate 31 | def dispLocalInfo(self): 32 | self.dispScreen(self.info.screen1) 33 | 34 | #Display Pool Name \n Remote hashrate 35 | def dispPoolInfo(self): 36 | self.dispScreen(self.info.screen2) 37 | 38 | #Display Rewards (confirmed + unconfirmed) \n Current Hash 39 | def dispRewardsInfo(self): 40 | self.dispScreen(self.info.screen3) 41 | 42 | #Display Error rate & Uptime 43 | def dispUptimeInfo(self): 44 | self.dispScreen(self.info.screen4) 45 | 46 | #Display rewards & price 47 | def dispValueInfo(self): 48 | self.dispScreen(self.info.screen5) 49 | 50 | #Send text to display 51 | def dispScreen(self, newScreen): 52 | self.screen = newScreen 53 | try: 54 | self.maxOffset = max((len(self.screen[0]) - 16), (len(self.screen[1]) - 16)) 55 | self.lcd.clear() 56 | s = self.screen[0] + '\n' + self.screen[1] 57 | self.lcd.message(s) 58 | except TypeError: 59 | self.lcd.clear() 60 | self.lcd.message('connecting\nto cgminer ...') 61 | 62 | 63 | #Cycle Backlight Color / On/Off 64 | def backlightStep(self): 65 | if self.prevCol is (len(self.col) -1): self.prevCol = -1 66 | newCol = self.prevCol + 1 67 | self.lcd.backlight(self.col[newCol]) 68 | self.prevCol = newCol 69 | 70 | #Offset text to the right 71 | def scrollLeft(self): 72 | if self.offset >= self.maxOffset: return 73 | self.lcd.scrollDisplayLeft() 74 | self.offset += 1 75 | 76 | #Offset text to the left 77 | def scrollRight(self): 78 | if self.offset <= 0: return 79 | self.lcd.scrollDisplayRight() 80 | self.offset -= 1 81 | 82 | #Display next info screen 83 | def modeUp(self): 84 | self.mode += 1 85 | if self.mode > 4: self.mode = 0 86 | self.update() 87 | 88 | #Display previous info screen 89 | def modeDown(self): 90 | self.mode -= 1 91 | if self.mode < 0: self.mode = 4 92 | self.update() 93 | 94 | #Update display 95 | def update(self): 96 | self.info.refresh() 97 | if self.mode == 0: self.dispPoolInfo() 98 | elif self.mode == 1: self.dispLocalInfo() 99 | elif self.mode == 2: self.dispRewardsInfo() 100 | elif self.mode == 3: self.dispUptimeInfo() 101 | elif self.mode == 4: self.dispValueInfo() 102 | -------------------------------------------------------------------------------- /opt/scripta/modules/PiMiner/PiMinerInfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #This file uses code from fcicq's cgmonitor.py released under GPLv3: 4 | #https://gist.github.com/fcicq/4975730 5 | #for details see LICENSE.txt 6 | 7 | import subprocess 8 | import socket 9 | import time 10 | import urllib 11 | import json 12 | import time 13 | 14 | class PiMinerInfo: 15 | 16 | host = '' 17 | port = 4028 18 | errRate = 0.0 19 | accepted = 0.0 20 | hw = 0.0 21 | diff1shares = 0.0 22 | uptime = '' 23 | screen1 = ['no data','no data'] 24 | screen2 = ['no data','no data'] 25 | screen3 = ['no data','no data'] 26 | screen4 = ['no data','no data'] 27 | screen5 = ['no data','no data'] 28 | currency = 'USD' #USD GBP EUR JPY AUD CAD CHF CNY DKK HKD PLN RUB SEK SGD THB NOK CZK 29 | dollars = ['USD', 'AUD', 'CAD'] #currencies with displayable symbols 30 | lastCheck = time.time() #time of last price check 31 | priceWait = 60.0 #interval between price checks 32 | priceLast = '-' #last price via mtgox 33 | priceLo = '-' #low price 34 | priceHi = '-' #high price 35 | 36 | def __init__(self): 37 | self.host = self.get_ipaddress() 38 | self.refresh() 39 | self.checkPrice() 40 | 41 | def reportError(self, s): 42 | self.screen1 = [s, s] 43 | self.screen2 = [s, s] 44 | self.screen3 = [s, s] 45 | self.screen4 = [s, s] 46 | 47 | def value_split(self, s): 48 | r = s.split('=') 49 | if len(r) == 2: return r 50 | return r[0], '' 51 | 52 | def response_split(self, s): 53 | try: 54 | r = s.split(',') 55 | title = r[0] 56 | d = dict(map(self.value_split, r[1:])) 57 | return title, d 58 | except ValueError: 59 | self.reportError('value error') 60 | 61 | def get_ipaddress(self): 62 | arg = 'ip route list' 63 | p = subprocess.Popen(arg,shell=True,stdout=subprocess.PIPE) 64 | data = p.communicate() 65 | split_data = data[0].split() 66 | self.ipaddr = split_data[split_data.index('src')+1] 67 | s = '%s' % self.ipaddr 68 | self.reportError(s) 69 | return self.ipaddr 70 | 71 | def parse_time(self, t): 72 | r = [] 73 | m = t // 60 74 | d = 0 75 | if t >= 86400: 76 | d = t // 86400 77 | t = t % 86400 78 | r.append('%02d:%02d:%02d' % (d, t // 3600, (t % 3600) // 60)) #seconds == t % 60 79 | return ' '.join(r) 80 | 81 | def cg_rpc(self, host, port, command): 82 | try: 83 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 84 | s.connect((host, port)) 85 | s.sendall(command) 86 | time.sleep(0.02) 87 | data = s.recv(8192) 88 | s.close() 89 | except Exception as e: 90 | self.reportError(e) 91 | return 92 | if data: 93 | d = data.strip('\x00|').split('|') 94 | return map(self.response_split, d) 95 | return None 96 | 97 | def hashrate(self, h): 98 | u = 'Mh/s' 99 | if h >= 1000.0: 100 | u = 'Gh/s' 101 | h = h / 1000.0 102 | elif h >= 1000000.0: 103 | u = 'Th/s' 104 | h = h / 1000000.0 105 | s = '%s %s' % (h, u) 106 | return s 107 | 108 | def abbrev(self, v): 109 | v = int(v) 110 | if v >= 1000: 111 | va = float(v) / 1000.0 112 | vs = '%.1f' % va 113 | vs = vs.replace('.', 'k') 114 | return vs 115 | elif v >= 1000000: 116 | va = float(v) / 1000000.0 117 | vs = '%.1f' % va 118 | vs = vs.replace('.', 'm') 119 | return vs 120 | #billion 121 | else: 122 | return '%d' % v 123 | 124 | def parse_summary(self, r): 125 | if not (isinstance(r, (list, tuple)) and len(r) == 2): 126 | return 127 | try: 128 | if not r[0][0] == 'STATUS=S' and r[1][0] == 'SUMMARY': 129 | return 130 | d = r[1][1] 131 | self.uptime = self.parse_time(int(d['Elapsed'])) 132 | self.accepted = float(d['Accepted']) 133 | self.hw = float(d['Hardware Errors']) 134 | try: 135 | #self.errRate = self.hw / self.accepted * 100.0 136 | self.errRate = 100.0 * self.hw / (self.diff1shares + self.hw) 137 | except Exception as e: 138 | self.errRate = 0.0 139 | acc = self.abbrev(d['Accepted']) 140 | rej = self.abbrev(d['Rejected']) 141 | hw = self.abbrev(d['Hardware Errors']) 142 | s1 = 'A:%s R:%s H:%s' % (acc, rej, hw) 143 | s2 = 'avg:%s' % self.hashrate(float(d['MHS av'])) 144 | return [s1, s2] 145 | except Exception as e: 146 | return [str(e), str(e)] 147 | 148 | def conv_prio_dict(self, p): 149 | if isinstance(p, (tuple, list, )): 150 | try: 151 | pd = dict(p) 152 | except TypeError: 153 | pd = zip(p, range(len(p))) 154 | return pd 155 | if isinstance(p, dict): return p 156 | return {} 157 | 158 | def parse_pools(self, r): 159 | if not isinstance(r, (list, tuple)): return ['format', 'error'] 160 | 161 | try: 162 | if not r[0][0] == 'STATUS=S': return ['status', 'error'] 163 | remote_time = int(r[0][1]['When']) 164 | for rp in r[1:]: 165 | if rp[0][0:4] != 'POOL': continue 166 | d = rp[1] 167 | self.diff1shares = float(d['Diff1 Shares']) 168 | if d['URL'].startswith('stratum+tcp://'): d['URL'] = d['URL'][14:] 169 | if d['URL'].startswith('http://'): d['URL'] = d['URL'][7:] 170 | d['URL'] = d['URL'].rstrip('/') 171 | if d['Status'] == 'Alive': 172 | s1 = '%s' % d['URL'] 173 | s2 = '%s' % d['User'] 174 | return [s1, s2] 175 | except Exception as e: 176 | return [str(e), str(e)] 177 | 178 | def parse_config(self, r): 179 | if not isinstance(r, (list, tuple)): return 180 | try: 181 | if not r[0][0] == 'STATUS=S': return 182 | if not r[1][0] == 'CONFIG': return 183 | d = r[1][1] 184 | return 'devcs: %s' % (int(d.get('GPU Count','0')) + int(d.get('PGA Count','0')) + int(d.get('ASC Count','0'))) 185 | except Exception as e: 186 | return str(e) 187 | 188 | def parse_coin(self, r): 189 | if not isinstance(r, (list, tuple)): return 190 | try: 191 | d = r[1][1] 192 | return 'diff: %.2fm' % (float(d['Network Difficulty']) / 1000000.0) 193 | except Exception as e: 194 | return str(e) 195 | 196 | def checkPrice(self): 197 | try: 198 | url = 'https://data.mtgox.com/api/2/BTC***/money/ticker'.replace('***', self.currency) 199 | f = urllib.urlopen(url) 200 | except Exception as e: 201 | self.reportError(e) 202 | return None 203 | data = None 204 | if f: 205 | pricesData = f.read() 206 | prices_json = json.loads(pricesData) 207 | if prices_json and prices_json['result'] == 'success': 208 | data = prices_json['data'] 209 | 210 | #dollar symbol currencies 211 | if self.currency in self.dollars: 212 | self.priceLast = data['last']['display_short'] if data else '-' 213 | self.priceLo = data['low']['display_short'] if data else '-' 214 | a, self.priceLo = self.priceLo.split('$') 215 | self.priceHi = data['high']['display_short'] if data else '-' 216 | a, self.priceHi = self.priceHi.split('$') 217 | 218 | #non-compatible symbol currencies 219 | else: 220 | self.priceLast = ('%.2f ' % float(data['last']['value']) if data else '-') + self.currency 221 | self.priceLo = '%.2f' % float(data['low']['value']) if data else '-' 222 | self.priceHi = '%.2f' % float(data['high']['value']) if data else '-' 223 | 224 | def refresh(self): 225 | 226 | s = self.cg_rpc(self.host, self.port, 'summary') 227 | self.screen1 = self.parse_summary(s) 228 | 229 | s = self.cg_rpc(self.host, self.port, 'pools') 230 | self.screen3 = self.parse_pools(s) 231 | 232 | s = self.cg_rpc(self.host, self.port, 'config') 233 | self.screen2[0] = self.parse_config(s) 234 | s = self.cg_rpc(self.host, self.port, 'coin') 235 | self.screen4[1] = self.parse_coin(s) 236 | 237 | self.screen4[0] = 'time: %s' % self.uptime 238 | self.screen2[1] = 'error: %.2f%%' % self.errRate 239 | 240 | now = time.time() 241 | since = now - self.lastCheck 242 | if since >= self.priceWait: 243 | self.checkPrice() 244 | self.lastCheck = time.time() 245 | 246 | self.screen5[0] = 'last: %s' % self.priceLast 247 | self.screen5[1] = 'H:' + self.priceHi + ' L:' + self.priceLo 248 | -------------------------------------------------------------------------------- /opt/scripta/modules/PiMiner/README.md: -------------------------------------------------------------------------------- 1 | PiMiner v1.1 2 | ======= 3 | 4 | Python scripts for interfacing cgminer with the Adafruit 16x2 LCD + Keypad Kit for Raspberry Pi. 5 | 6 | Project tutorial: http://learn.adafruit.com/piminer-raspberry-pi-bitcoin-miner 7 | 8 | In progress! 9 | 10 | Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! 11 | 12 | Written by Collin Cunningham for Adafruit Industries. BSD license, all text above must be included in any redistribution 13 | 14 | To download, log into your Pi with Internet accessibility and type: git clone https://github.com/adafruit/PiMiner.git 15 | 16 | 17 | Changes 18 | ------------- 19 | 20 | Version 1.1 21 | - Added mining auto-start after boot (see tutorial) 22 | - Time format changed to dd:hh:mm 23 | - Abbreviated large share count; ex. "1k2" 24 | - Revised error % calculation: 100 * HW / (diff1shares + HW) 25 | - Added MtGox last, high, & low price ("currency" var can be set in script) 26 | - Misc. tutorial revisions 27 | 28 | 29 | Version 1.0 30 | - Initial release 31 | -------------------------------------------------------------------------------- /opt/scripta/modules/cgminerLCDStats/CgminerRPCClient.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # class to accesss cgminer via RPC API 4 | # 5 | 6 | import socket 7 | import urlparse 8 | import urllib 9 | import time 10 | import json 11 | 12 | # 13 | # execute cgminer API remote procedure call 14 | def command(command, host, port): 15 | try: 16 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 17 | s.connect((host, port)) 18 | s.sendall(json.dumps({"command": command})) # send API request formatted as json 19 | time.sleep(0.02) 20 | 21 | # loop until a zero byte indicates we got all the data 22 | data = "" 23 | while True: 24 | buffer = s.recv(65535) 25 | if '\x00' in buffer: 26 | data += buffer # keep the buffer and bail from the loop - we got all the data 27 | break # zero found, so we must have all the data TODO break in loop is ugly 28 | else: 29 | data += buffer # No zero found yet, append current buffer to data and loop for more 30 | 31 | s.close() # close the socket 32 | 33 | except Exception as e: 34 | print "API Exception executing command: " + command 35 | print str(e) # TODO conditonal logging 36 | raise Exception ("API Connection Error") 37 | 38 | if data: 39 | try: 40 | data = data.replace('\x00', '') # the null byte makes json decoding unhappy 41 | decoded = json.loads(data) # we sent a json request, so expect json response 42 | return decoded 43 | except: 44 | # TODO conditional loggging 45 | print "JSON decoding error - bad JSON sring:" 46 | print data 47 | pass # swallow the exception (normal use shouldn't throw one ?) 48 | 49 | -------------------------------------------------------------------------------- /opt/scripta/modules/cgminerLCDStats/MinePeon Install.md: -------------------------------------------------------------------------------- 1 | This is a quick guide to installing the cgminerLCDStats.py script on MinePeon. Note that I'm new to MinePeon as well as Arch linux for ARM. I welcome any input on this guide. 2 | 3 | I started with a fresh install of the current version of MinePeon, v0.2.2. I took the usual steps to verify cgminer was working correctly, and that my Pi would come up on the same internal I.P. address each time. 4 | 5 | To begin the installation, I logged in to the Pi via ssh from my main machine. I find it way easier to interact with the Pi command line over ssh, rather than logging into the Pi itself. When entering the following commands, it's easiest to copy and paste them into the terminal window. Wait for each step to complete and watch for errors. Some of the updates require user interaction, so say yes if prompted. 6 | 7 | Ok, let's get started. Log on to your Pi with this command: 8 | ssh minepeon@YOURIP - example: ssh minepeon@192.168.1.111 9 | 10 | Make sure the OS is up to date (Optional step - skip this is you want too, or are already on a recent version): 11 | `sudo pacman -Syu` 12 | 13 | Get the "git" utility for downloading packages: 14 | `sudo pacman -S git` 15 | 16 | Make sure we have all the latest MinePeon packages (Optional step - skip this is you want too, or are already on a recent version): 17 | `cd /opt/minepeon/` 18 | `git pull` 19 | `cd /opt/minepeon/http/` 20 | `git pull` 21 | 22 | Optional: Verify Python2 is already installed (it should be) - current version is Python 2.7.5: 23 | `python2 -V` 24 | 25 | Install pyUSB library: 26 | `cd ~` 27 | `git clone https://github.com/walac/pyusb.git` 28 | `cd pyusb` 29 | `sudo python2 setup.py install` 30 | 31 | Install the cgminerLCDStats.py script and required modules: 32 | `cd ~` 33 | `git clone https://github.com/cardcomm/cgminerLCDStats.git` 34 | `cd cgminerLCDStats` 35 | 36 | Ok, that's it. We should be ready to go. Make sure the LCD display is connected, and let's start the script. You can start it with the default options using the following command: 37 | `sudo python2 cgminerLCDStats.py` 38 | 39 | If everything went well, you should now see your cgminer stats displayed on the USB screen. Enjoy! 40 | 41 | Note: By default, the display refreshes every 30 seconds. You can change this, and other behavior using the following command line options: 42 | 43 | Options: 44 | -h, --help show this help message and exit 45 | -s, --simple Show simple display layout instead of default 46 | -d REFRESHDELAY, --refresh-delay=REFRESHDELAY 47 | REFRESHDELAY = Time delay between screen/API refresh 48 | -i HOST, --host=HOST I.P. Address of cgminer API host 49 | 50 | -------------------------------------------------------------------------------- /opt/scripta/modules/cgminerLCDStats/README.md: -------------------------------------------------------------------------------- 1 | cgminerLCDStats 2 | =============== 3 | 4 | Simple script to get data from cgminer API and display it on the "LCD sys info" display. See links below for where you can purchase the display used for this project. 5 | 6 | If you feel this code is useful, please consider a donation to: 7 | BTC address: 15aGZp2pCbpAFHcjHVrx2G746PXFo9VEed 8 | 9 | Run as root to avoid permissions issues : sudo python cgminerLCDStats.py [options] 10 | 11 | Usage: cgminerLCDStats.py [options] arg 12 | 13 | Options: 14 | `-h, --help show this help message and exit` 15 | `-s, --simple Show simple display layout instead of default` 16 | `-d REFRESHDELAY, --refresh-delay=REFRESHDELAY where REFRESHDELAY = Time delay between screen/API refresh` 17 | `-i HOST, --host=HOST I.P. Address of cgminer API host` 18 | `-c TIMEDISPLAYFORMAT, --clock=TIMEDISPLAYFORMAT Options 12 or 24 - Clock Display 12hr / 24hr` 19 | 20 | Where to buy the LCD Display Unit: 21 | http://www.ebay.com/itm/USB-2-8-TFT-LCD-module-LCD-sys-info-display-temperature-fan-AIDA64-LCD-Smartie-/121004607232?pt=LH_DefaultDomain_0&hash=item1c2c6fc700 22 | 23 | For more specifics about the "LCD sys info" display this code supports, see: 24 | http://coldtearselectronics.wikispaces.com/USB+LCD+-+LCD+System+info 25 | https://github.com/dangardner/pylcdsysinfo 26 | 27 | Note: A HUGE thank you goes out to Kano for is invaluable assitance with this code. 28 | He's a key developer on the cgminer project, and was a big help in sorting out problems I had writing this script. 29 | https://bitcointalk.org/index.php?action=profile;u=36044 30 | 31 | Copyright (c) 2013 Cardinal Commmunications 32 | 33 | Permission to use, copy, modify, and/or distribute this software for any 34 | purpose with or without fee is hereby granted, provided that the above 35 | copyright notice and this permission notice appear in all copies. 36 | 37 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 38 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 39 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 40 | SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 41 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 42 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 43 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44 | 45 | Please check the library code module "pylcdsysinfo.py" for copyright and author information. 46 | -------------------------------------------------------------------------------- /opt/scripta/modules/cgminerLCDStats/lcd_and_pi-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/modules/cgminerLCDStats/lcd_and_pi-small.jpg -------------------------------------------------------------------------------- /opt/scripta/modules/cgminerLCDStats/lcd_and_pi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/modules/cgminerLCDStats/lcd_and_pi.jpg -------------------------------------------------------------------------------- /opt/scripta/startup/miner-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo /usr/sbin/ntpdate -u pool.ntp.org 3 | sudo /usr/bin/screen -dmS bfgminer /opt/scripta/bin/bfgminer -c /opt/scripta/etc/miner.conf 4 | sleep 1 5 | echo `pidof bfgminer` > /opt/scripta/var/bfgminer.pid 6 | 7 | 8 | -------------------------------------------------------------------------------- /opt/scripta/startup/miner-stop.sh: -------------------------------------------------------------------------------- 1 | #sudo kill $(cat /opt/scripta/var/cgminer.lock) 2 | 3 | sudo /usr/bin/screen -S bfgminer -X quit 4 | -------------------------------------------------------------------------------- /opt/scripta/var/rrd/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/opt/scripta/var/rrd/.keep -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /usr/bin/screen -S bfgminer -X quit 3 | cd / 4 | git pull 5 | sudo cp -Ru /scripta/etc/rc.local /etc/rc.local 6 | sudo cp -Ru /scripta/opt/scripta/ /opt/ 7 | sudo cp -Ru /scripta/var/ / 8 | sudo cp -Ru /scripta/update.sh /update.sh 9 | sudo chown -R www-data:www-data /opt/scripta 10 | sudo chown -R www-data:www-data /var/www 11 | sudo chmod -R 775 /opt/scripta/startup/*.sh 12 | sudo chmod -R 775 /etc/rc.local 13 | sudo chmod -R 775 /var/www 14 | sleep 5 15 | sudo reboot 16 | -------------------------------------------------------------------------------- /var/spool/cron/crontabs/root: -------------------------------------------------------------------------------- 1 | # DO NOT EDIT THIS FILE - edit the master and reinstall. 2 | # (/tmp/crontab.NXCETO/crontab installed on Wed Apr 16 21:19:35 2014) 3 | # (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $) 4 | # Edit this file to introduce tasks to be run by cron. 5 | # 6 | # Each task to run has to be defined through a single line 7 | # indicating with different fields when the task will be run 8 | # and what command to run for the task 9 | # 10 | # To define the time you can provide concrete values for 11 | # minute (m), hour (h), day of month (dom), month (mon), 12 | # and day of week (dow) or use '*' in these fields (for 'any').# 13 | # Notice that tasks will be started based on the cron's system 14 | # daemon's notion of time and timezones. 15 | # 16 | # Output of the crontab jobs (including errors) is sent through 17 | # email to the user the crontab file belongs to (unless redirected). 18 | # 19 | # For example, you can run a backup of all your user accounts 20 | # at 5 a.m every week with: 21 | # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ 22 | # 23 | # For more information see the manual pages of crontab(5) and cron(8) 24 | # 25 | # m h dom mon dow command 26 | 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/bin/php5 /opt/scripta/etc/cron.d/5min/ALERTdeviceCount 27 | 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/bin/php5 /opt/scripta/etc/cron.d/5min/ALERThashrate 28 | 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/bin/php5 /opt/scripta/etc/cron.d/5min/hashrate 29 | 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/bin/php5 /opt/scripta/etc/cron.d/5min/temp 30 | 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/bin/php5 /opt/scripta/etc/cron.d/5min/RECORDhashrate 31 | -------------------------------------------------------------------------------- /var/www/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /var/www/css/alertify.css: -------------------------------------------------------------------------------- 1 | /*! alertify 0.4.0rc1 (Fabien Doiron) | MIT */ 2 | /* alertify-transitions */ 3 | .alertify-cover{position:fixed;z-index:9999;top:0;bottom:0;left:0;right:0;}.alertify-dialog{position:fixed;z-index:99999;top:50px;left:50%;opacity:1;-webkit-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);-moz-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);-ms-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);-o-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);}.alertify-resetFocus{border:0;clip:rect(0000);height:1px;width:1px;overflow:hidden;position:absolute;margin:-1px;padding:0;}.alertify-text{margin-bottom:15px;width:100%;font-size:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}.alertify-button,.alertify-button:hover,.alertify-button:active,.alertify-button:visited{background:none;text-decoration:none;border:none;line-height:1.5;font-size:100%;display:inline-block;cursor:pointer;margin-left:5px;}.is-alertify-cover-hidden{display:none;}.is-alertify-dialog-hidden{opacity:0;display:none;-webkit-transform:translate(0,-150px);-moz-transform:translate(0,-150px);-ms-transform:translate(0,-150px);-o-transform:translate(0,-150px);transform:translate(0,-150px);}:root * > .is-alertify-dialog-hidden{display:block;}.alertify-logs{position:fixed;z-index:9999;}.alertify-log{position:relative;display:block;opacity:0;-webkit-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);-moz-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);-ms-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);-o-transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);transition:all 500ms cubic-bezier(0.175,0.885,0.32,1.275);}.is-alertify-log-showing{opacity:1;}.is-alertify-log-hidden{opacity:0;} 4 | /* alertify-default */ 5 | .alertify-dialog{width:550px;margin-left:-275px;background:#FFF;border:10px solid rgba(0,0,0,0.7);border-radius:8px;box-shadow:0 3px 3px rgba(0,0,0,0.3);-webkit-background-clip:padding;-moz-background-clip:padding;background-clip:padding-box;}.alertify-dialog-inner{padding:25px;}.alertify-inner{text-align:center;}.alertify-text{border:1px solid #ccc;border-radius:4px;padding:10px;}.alertify-button{border-radius:4px;color:#FFF;font-weight:700;text-decoration:none;text-shadow:1px 1px 0 rgba(0,0,0,0.5);box-shadow:inset 0 1px 0 0 rgba(255,255,255,0.5);background-image:linear-gradient(top,rgba(255,255,255,0.3), rgba(255,255,255,0));padding:6px 15px;}.alertify-button:hover,.alertify-button:focus{outline:none;background-image:linear-gradient(top,rgba(0,0,0,0.1), rgba(0,0,0,0));}.alertify-button:focus{box-shadow:0 0 10px #2b72d5;}.alertify-button:active{position:relative;box-shadow:inset 0 2px 4px rgba(0,0,0,0.15), 0 1px 2px rgba(0,0,0,0.05);}.alertify-button-cancel,.alertify-button-cancel:hover,.alertify-button-cancel:focus{background-color:#fe1a00;border:1px solid #cb1500;}.alertify-button-ok,.alertify-button-ok:hover,.alertify-button-ok:focus{background-color:#5cb811;border:1px solid #45890d;}.alertify-logs{position:fixed;z-index:9999;bottom:8px;right:8px;width:300px;}.alertify-log{margin-top:8px;right:-300px;border-radius:4px;padding:16px;}.alertify-log-info{background:rgba(0,0,0,0.9);color:#FFF;text-shadow:-1px -1px 0 rgba(0,0,0,0.5);}.alertify-log-error{color:#FFF;background:rgba(254,26,0,0.9);}.alertify-log-success{color:#FFF;background:rgba(92,184,17,0.9);}.is-alertify-log-showing{right:0;}.is-alertify-log-hidden{right:-300px;}@media only screen and max-width 680px{.alertify-dialog{width:90%;left:5%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;}} 6 | -------------------------------------------------------------------------------- /var/www/css/custom.css: -------------------------------------------------------------------------------- 1 | body 2 | { 3 | font-family: 'News Cycle', sans-serif; 4 | color: #222; 5 | line-height: 1.4; 6 | text-rendering: optimizeLegibility; 7 | /* -webkit-text-stroke: 0.35px; */ 8 | } 9 | 10 | h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { 11 | font-family: 'News Cycle', sans-serif; 12 | font-weight: 700; 13 | line-height: 1.1; 14 | } 15 | 16 | a, .btn { color: #68a72f; } 17 | a:hover, a:focus, .btn:hover { color: #076633; } 18 | .btn, .input-group-addon, .form-control { border-radius: 2px; } 19 | .btn 20 | { 21 | font-weight: 700; 22 | line-height: 1.45em; 23 | background-color: #F4F4F4; 24 | } 25 | 26 | footer { color: #aaa; } 27 | 28 | /* repeat bootstrap btns */ 29 | .btn-primary { 30 | color: #fff; 31 | background-color: #428bca; 32 | border-color: #357ebd 33 | } 34 | 35 | .btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, 36 | .open .dropdown-toggle.btn-primary { 37 | color: #fff; 38 | background-color: #3276b1; 39 | border-color: #285e8e 40 | } 41 | 42 | .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary { 43 | background-image: none 44 | } 45 | 46 | .btn-primary.disabled, .btn-primary[disabled], fieldset[disabled] .btn-primary, 47 | .btn-primary.disabled:hover, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary:hover, 48 | .btn-primary.disabled:focus, .btn-primary[disabled]:focus, fieldset[disabled] .btn-primary:focus, 49 | .btn-primary.disabled:active, .btn-primary[disabled]:active, fieldset[disabled] .btn-primary:active, 50 | .btn-primary.disabled.active, .btn-primary[disabled].active, fieldset[disabled] .btn-primary.active { 51 | background-color: #428bca; 52 | border-color: #357ebd 53 | } 54 | 55 | .btn-warning { 56 | color: #fff; 57 | background-color: #f0ad4e; 58 | border-color: #eea236 59 | } 60 | 61 | .btn-warning:hover, .btn-warning:focus, .btn-warning:active, .btn-warning.active, 62 | .open .dropdown-toggle.btn-warning { 63 | color: #fff; 64 | background-color: #ed9c28; 65 | border-color: #d58512 66 | } 67 | 68 | .btn-warning:active, .btn-warning.active, .open .dropdown-toggle.btn-warning { 69 | background-image: none 70 | } 71 | 72 | .btn-warning.disabled, .btn-warning[disabled], fieldset[disabled] .btn-warning, 73 | .btn-warning.disabled:hover, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning:hover, 74 | .btn-warning.disabled:focus, .btn-warning[disabled]:focus, fieldset[disabled] .btn-warning:focus, 75 | .btn-warning.disabled:active, .btn-warning[disabled]:active, fieldset[disabled] .btn-warning:active, 76 | .btn-warning.disabled.active, .btn-warning[disabled].active, fieldset[disabled] .btn-warning.active { 77 | background-color: #f0ad4e; 78 | border-color: #eea236 79 | } 80 | 81 | .btn-danger { 82 | color: #fff; 83 | background-color: #d9534f; 84 | border-color: #d43f3a 85 | } 86 | 87 | .btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active, 88 | .open .dropdown-toggle.btn-danger { 89 | color: #fff; 90 | background-color: #d2322d; 91 | border-color: #ac2925 92 | } 93 | /* */ 94 | 95 | .alertify-logs {font-weight:700;} 96 | 97 | /* header.navbar { position: fixed; width: 100%; } */ 98 | header.navbar .container 99 | { 100 | background-color: transparent; 101 | background-image: url(../img/bg-header1.png); 102 | background-repeat: no-repeat; 103 | background-position: 100% 100%; 104 | } 105 | 106 | .navbar-default { border-color: #9DD374; } 107 | .navbar-brand { height: 140px; } 108 | .navbar-brand img { height: 100%; } 109 | 110 | .navbar-collapse.collapse { position: relative; } 111 | .nav.navbar-nav {position: absolute; bottom: 0; left: 280px} 112 | .navbar-nav.navbar-right { position: absolute; right: 20px; bottom: 0; } 113 | 114 | .navbar-nav > li { font-weight: bold; } 115 | .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav>.active>a:hover 116 | { 117 | color: #fff; 118 | background-color: #9DD374; 119 | border-radius: 2px; 120 | border-bottom-left-radius: 0; 121 | border-bottom-right-radius: 0; 122 | } 123 | 124 | .list-group-item 125 | { 126 | border-width: 1px 0 1px 0; 127 | border-color: #D5D5D5; 128 | } 129 | /* 130 | .list-group-item:first-child { 131 | border-top-right-radius: 2px; 132 | border-top-left-radius: 2px; 133 | } 134 | */ 135 | 136 | a.list-group-item:hover, a.list-group-item:focus { 137 | margin-right: -20px; 138 | padding-right: 40px; 139 | color: #111; 140 | } 141 | 142 | a.list-group-item:hover:after, a.list-group-item:focus:after 143 | { 144 | content: '>'; 145 | position: absolute; 146 | right: 0; 147 | top: 0; 148 | bottom: 0; 149 | padding: 4px; 150 | font-size: 2em; 151 | line-height: 1em; 152 | color: #090; 153 | } -------------------------------------------------------------------------------- /var/www/css/theme.css: -------------------------------------------------------------------------------- 1 | 2 | /* Structure */ 3 | body{ 4 | padding-bottom: 50px; 5 | } 6 | .navbar{ 7 | margin-bottom: 0px; 8 | } 9 | .container.down{ 10 | opacity: .5 11 | } 12 | 13 | /* Display on hover */ 14 | .scripta-trigger .scripta-more{ 15 | display: none; 16 | } 17 | .scripta-trigger:hover .scripta-more{ 18 | display: inline-block; 19 | } 20 | 21 | /* Status charts */ 22 | .graph-live{ 23 | height: 159px; 24 | width: 100% 25 | } 26 | 27 | /* Status tables */ 28 | td,th{ 29 | white-space: nowrap; 30 | } 31 | .table-right td,.table-right tfoot th{ 32 | text-align: right 33 | } 34 | .table-right td.text-left,.table-right tfoot th.text-left{ 35 | text-align: left 36 | } 37 | tr.text-muted{ 38 | background: #f5f5f5; 39 | } 40 | 41 | /* Index / Shorten wide values in tables and show them on hover */ 42 | .ellipsis{ 43 | overflow: hidden; 44 | text-overflow: ellipsis; 45 | -o-text-overflow: ellipsis; 46 | white-space: nowrap; 47 | max-width: 80px; 48 | } 49 | .ellipsis:hover{ 50 | overflow: visible; 51 | max-width:none; 52 | width:auto; 53 | background-color: #fff!important; 54 | } 55 | 56 | /* Settings */ 57 | input:required:invalid{ 58 | border-color: rgb(233, 50, 45); 59 | box-shadow: 0px 0px 6px rgb(248, 185, 183); 60 | color: rgb(185, 74, 72); 61 | border-color: rgb(238, 95, 91); 62 | } 63 | -------------------------------------------------------------------------------- /var/www/f_backup.php: -------------------------------------------------------------------------------- 1 | 'success', 'text' => 'Backup saved'); 47 | foreach ($items as $key => $value) { 48 | if($value['selected']){ 49 | $r['data'][$key]=secure_copy($baseFolder.$value['name'],$backupFolder.$_REQUEST['name'].'/'.$value['name']); 50 | } 51 | } 52 | } 53 | else{ 54 | $r['info'][]=array('type' => 'success', 'text' => 'Backup not saved'); 55 | } 56 | } 57 | 58 | // Copy folder from backupFolder back to baseFolder 59 | elseif (!empty($_REQUEST['restore']) && @is_dir($backupFolder.$_REQUEST['restore'])) { 60 | $restore = $_REQUEST['restore']; 61 | 62 | // Scan backup and remove . & .. 63 | $items = @scandir($backupFolder.$restore); 64 | if(!empty($items)){ 65 | array_shift($items); 66 | array_shift($items); 67 | $r['info'][]=array('type' => 'success', 'text' => 'Restored!'); 68 | } 69 | else{ 70 | $r['info'][]=array('type' => 'danger', 'text' => 'Could not find backup'); 71 | } 72 | foreach ($items as $key => $value) { 73 | // To return success: $r['data'][$key]=... 74 | secure_copy($backupFolder.$restore .'/'.$value,$baseFolder.$value); 75 | } 76 | } 77 | 78 | // Get a list of all backups and their content 79 | else{ 80 | // Scan backup folder and remove . & .. 81 | $items = @scandir($backupFolder); 82 | if(!empty($items)){ 83 | array_shift($items); 84 | array_shift($items); 85 | } 86 | else{exit;} 87 | rsort($items); 88 | 89 | // Scan subfolders, in the future this should also return the files 90 | foreach ($items as $key => $value) { 91 | $r['data'][$key]['dir']=$value; 92 | $r['data'][$key]['items']=@scandir($backupFolder.'/'.$value); 93 | if(!empty($r['data'][$key]['items'])){ 94 | array_shift($r['data'][$key]['items']); 95 | array_shift($r['data'][$key]['items']); 96 | } 97 | } 98 | } 99 | 100 | echo json_encode($r); 101 | ?> 102 | -------------------------------------------------------------------------------- /var/www/f_graph.php: -------------------------------------------------------------------------------- 1 | 43 | -------------------------------------------------------------------------------- /var/www/f_hostHardCtl.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /var/www/f_login.php: -------------------------------------------------------------------------------- 1 | 35 | -------------------------------------------------------------------------------- /var/www/f_logout.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /var/www/f_miner.php: -------------------------------------------------------------------------------- 1 | 29 | -------------------------------------------------------------------------------- /var/www/f_minerHardCtl.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /var/www/f_minercompat.php: -------------------------------------------------------------------------------- 1 | $value) { 21 | if($key=='pools'){ 22 | $r['data']['pools']=$value; 23 | } 24 | else{ 25 | $r['data']['options'][]=array('key'=>$key,'value'=>$value); 26 | } 27 | } 28 | file_put_contents($configPools, json_encode($r['data']['pools'], JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK)); 29 | file_put_contents($configOptns, json_encode($r['data']['options'], JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK)); 30 | $r['info'][]=array('type' => 'success', 'text' => 'Compatibility reload done'); 31 | } 32 | else{ 33 | $r['info'][]=array('type' => 'error', 'text' => 'miner.conf not found'); 34 | } 35 | 36 | echo json_encode($r); 37 | ?> 38 | -------------------------------------------------------------------------------- /var/www/f_settings copy.php: -------------------------------------------------------------------------------- 1 | 0) { 28 | file_put_contents($configUipwd,'scripta:' . md5($pass) ); 29 | $r['info'][]=array('type' => 'success', 'text' => 'Web password saved'); 30 | } 31 | } 32 | 33 | // Manage settings 34 | elseif (!empty($_REQUEST['settings'])) { 35 | $newdata = json_decode($_REQUEST['settings'], true); 36 | $r['data'] = json_decode(@file_get_contents($configScripta), true); 37 | 38 | // Sync current with new settings 39 | if(!empty($newdata)&&is_array($newdata)){ 40 | foreach ($newdata as $key => $value) { 41 | $r['data'][$key]=$value; 42 | } 43 | file_put_contents($configScripta, json_encode($r['data'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 44 | $r['info'][]=array('type' => 'success', 'text' => 'Configuration saved'); 45 | } 46 | // Load current settings 47 | else{ 48 | $r['info'][]=array('type' => 'info', 'text' => 'Configuration loaded'); 49 | } 50 | 51 | if(isset($r['data']['userTimezone'])){ 52 | date_default_timezone_set($r['data']['userTimezone']); 53 | $r['data']['date'] = date('Y-m-d H:i:s'); 54 | } 55 | } 56 | 57 | // Manage pools 58 | elseif (!empty($_REQUEST['pools'])) { 59 | $newdata = json_decode($_REQUEST['pools'], true); 60 | $r['data'] = json_decode(@file_get_contents($configPools), true); 61 | 62 | foreach ($r['data'] as $id => $p) 63 | { 64 | $r['data'][$id]['url'] = str_replace('stratum tcp','stratum+tcp',$p['url']); 65 | } 66 | $m=0; 67 | foreach ($newdata as $id => $p) 68 | { 69 | $newdata[$id]['url'] = str_replace('stratum tcp','stratum+tcp',$p['url']); 70 | if($p['prio'] > $m) $m=$p['prio']; 71 | } 72 | 73 | ChromePhp::log($newdata); 74 | ChromePhp::log($m); 75 | 76 | if($m>0){ 77 | $pl=array(); 78 | for ($pp = 0; $pp <= $m; $pp++) { 79 | foreach ($newdata as $id => $p){ 80 | if($p['prio'] == $pp) $pl[]=$newdata[$id]; 81 | } 82 | } 83 | $newdata = $pl; 84 | } 85 | 86 | // Overwrite current with new pools 87 | if(!empty($newdata)&&is_array($newdata)){ 88 | file_put_contents($configPools, json_encode($newdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 89 | minerConfigGenerate(); 90 | $r['data']=$newdata; 91 | $r['info'][]=array('type' => 'success', 'text' => 'Pools config saved'); 92 | } 93 | // Load current settings 94 | elseif(!empty($r['data'])&&is_array($r['data'])){ 95 | $r['info'][]=array('type' => 'info', 'text' => 'Pools config loaded'); 96 | } 97 | // Load new settings 98 | else{ 99 | $r['data']=array(array('url'=>'empty')); 100 | $r['info'][]=array('type' => 'error', 'text' => 'Pools config not found'); 101 | } 102 | } 103 | 104 | // Manage miner.conf 105 | elseif (!empty($_REQUEST['options'])) { 106 | $newdata = json_decode($_REQUEST['options'], true); 107 | $r['data'] = json_decode(@file_get_contents($configOptns), true); 108 | 109 | // Overwrite current with new config 110 | if(!empty($newdata)&&is_array($newdata)){ 111 | file_put_contents($configOptns, json_encode($newdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 112 | minerConfigGenerate(); 113 | $r['data']=$newdata; 114 | $r['info'][]=array('type' => 'success', 'text' => 'Miner options saved'); 115 | } 116 | // Load current settings 117 | elseif(!empty($r['data'])&&is_array($r['data'])){ 118 | $r['info'][]=array('type' => 'info', 'text' => 'Miner options loaded'); 119 | } 120 | // Load new settings 121 | else{ 122 | $r['data']=array(array('key'=>'algo','value'=>'c')); 123 | $r['info'][]=array('type' => 'error', 'text' => 'Miner options not found'); 124 | } 125 | } 126 | 127 | // Set system timezone to what is stored in settings 128 | elseif (!empty($_REQUEST['timezone'])) { 129 | $timezone = json_decode($_REQUEST['timezone']); 130 | ini_set( 'date.timezone', $timezone ); 131 | putenv('TZ=' . $timezone); 132 | date_default_timezone_set($timezone); 133 | $r['data']['date'] = date('Y-m-d H:i:s'); 134 | $r['info'][]=array('type' => 'info', 'text' => 'Timezone is '.$timezone ); 135 | } 136 | 137 | echo json_encode($r); 138 | 139 | function minerConfigGenerate(){ 140 | global $configOptns,$configPools,$configMiner; 141 | $options = json_decode(@file_get_contents($configOptns), true); 142 | 143 | // Angular objects ==> miner 144 | // {key:k,value:v} ==> {k:v} 145 | foreach ($options as $o) { 146 | $miner[$o['key']]=$o['value']; 147 | } 148 | 149 | $miner['pools']= json_decode(@file_get_contents($configPools), true); 150 | file_put_contents($configMiner, json_encode($miner, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 151 | } 152 | ?> 153 | -------------------------------------------------------------------------------- /var/www/f_settings.php: -------------------------------------------------------------------------------- 1 | 0) { 28 | file_put_contents($configUipwd,'scripta:' . md5($pass) ); 29 | $r['info'][]=array('type' => 'success', 'text' => 'Web password saved'); 30 | } 31 | } 32 | 33 | // Manage settings 34 | elseif (!empty($_REQUEST['settings'])) { 35 | $newdata = json_decode($_REQUEST['settings'], true); 36 | $r['data'] = json_decode(@file_get_contents($configScripta), true); 37 | 38 | // Sync current with new settings 39 | if(!empty($newdata)&&is_array($newdata)){ 40 | foreach ($newdata as $key => $value) { 41 | $r['data'][$key]=$value; 42 | } 43 | file_put_contents($configScripta, json_encode($r['data'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 44 | $r['info'][]=array('type' => 'success', 'text' => 'Configuration saved'); 45 | } 46 | // Load current settings 47 | else{ 48 | $r['info'][]=array('type' => 'info', 'text' => 'Configuration loaded'); 49 | } 50 | 51 | if(isset($r['data']['userTimezone'])){ 52 | date_default_timezone_set($r['data']['userTimezone']); 53 | $r['data']['date'] = date('Y-m-d H:i:s'); 54 | } 55 | } 56 | 57 | // Manage pools 58 | elseif (!empty($_REQUEST['pools'])) { 59 | $newdata = json_decode($_REQUEST['pools'], true); 60 | $r['data'] = json_decode(@file_get_contents($configPools), true); 61 | 62 | foreach ($r['data'] as $id => $p) 63 | { 64 | $r['data'][$id]['url'] = str_replace('stratum tcp','stratum+tcp',$p['url']); 65 | } 66 | $m=0; 67 | foreach ($newdata as $id => $p) 68 | { 69 | $newdata[$id]['url'] = str_replace('stratum tcp','stratum+tcp',$p['url']); 70 | if($p['prio'] > $m) $m=$p['prio']; 71 | } 72 | 73 | ChromePhp::log($newdata); 74 | ChromePhp::log($m); 75 | 76 | if($m>0){ 77 | $pl=array(); 78 | for ($pp = 0; $pp <= $m; $pp++) { 79 | foreach ($newdata as $id => $p){ 80 | if($p['prio'] == $pp) $pl[]=$newdata[$id]; 81 | } 82 | } 83 | $newdata = $pl; 84 | } 85 | 86 | // Overwrite current with new pools 87 | if(!empty($newdata)&&is_array($newdata)){ 88 | file_put_contents($configPools, json_encode($newdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 89 | minerConfigGenerate(); 90 | $r['data']=$newdata; 91 | $r['info'][]=array('type' => 'success', 'text' => 'Pools config saved'); 92 | } 93 | // Load current settings 94 | elseif(!empty($r['data'])&&is_array($r['data'])){ 95 | $r['info'][]=array('type' => 'info', 'text' => 'Pools config loaded'); 96 | } 97 | // Load new settings 98 | else{ 99 | $r['data']=array(array('url'=>'empty')); 100 | $r['info'][]=array('type' => 'error', 'text' => 'Pools config not found'); 101 | } 102 | } 103 | 104 | // Manage miner.conf 105 | elseif (!empty($_REQUEST['options'])) { 106 | $newdata = json_decode($_REQUEST['options'], true); 107 | $r['data'] = json_decode(@file_get_contents($configOptns), true); 108 | 109 | // Overwrite current with new config 110 | if(!empty($newdata)&&is_array($newdata)){ 111 | file_put_contents($configOptns, json_encode($newdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 112 | minerConfigGenerate(); 113 | $r['data']=$newdata; 114 | $r['info'][]=array('type' => 'success', 'text' => 'Miner options saved'); 115 | } 116 | // Load current settings 117 | elseif(!empty($r['data'])&&is_array($r['data'])){ 118 | $r['info'][]=array('type' => 'info', 'text' => 'Miner options loaded'); 119 | } 120 | // Load new settings 121 | else{ 122 | $r['data']=array(array('key'=>'algo','value'=>'c')); 123 | $r['info'][]=array('type' => 'error', 'text' => 'Miner options not found'); 124 | } 125 | } 126 | 127 | // Set system timezone to what is stored in settings 128 | elseif (!empty($_REQUEST['timezone'])) { 129 | $timezone = json_decode($_REQUEST['timezone']); 130 | ini_set( 'date.timezone', $timezone ); 131 | putenv('TZ=' . $timezone); 132 | date_default_timezone_set($timezone); 133 | $r['data']['date'] = date('Y-m-d H:i:s'); 134 | $r['info'][]=array('type' => 'info', 'text' => 'Timezone is '.$timezone ); 135 | } 136 | 137 | echo json_encode($r); 138 | 139 | function minerConfigGenerate(){ 140 | global $configOptns,$configPools,$configMiner; 141 | $options = json_decode(@file_get_contents($configOptns), true); 142 | 143 | // Angular objects ==> miner 144 | // {key:k,value:v} ==> {k:v} 145 | foreach ($options as $o) { 146 | $miner[$o['key']]=$o['value']; 147 | } 148 | 149 | $miner['pools']= json_decode(@file_get_contents($configPools), true); 150 | file_put_contents($configMiner, json_encode($miner, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 151 | } 152 | ?> 153 | -------------------------------------------------------------------------------- /var/www/f_status.php: -------------------------------------------------------------------------------- 1 | 'Hoeba','ID'=>0,'Temperature'=>rand(20,35),'MHS5s'=>rand(80000,100000),'MHSav'=>rand(90000,100000),'LongPoll'=>'N','Getworks'=>200,'Accepted'=>rand(70,200),'Rejected'=>rand(1,10),'HardwareErrors'=>rand(0,50),'Utility'=>1.2,'LastShareTime'=>time()-rand(0,10)); 42 | $r['status']['devs'][]=array('Name'=>'Debug','ID'=>1,'Temperature'=>rand(20,35),'MHS5s'=>rand(40000,50000),'MHSav'=>rand(45000,50000),'LongPoll'=>'N','Getworks'=>1076,'Accepted'=>1324,'Rejected'=>1,'HardwareErrors'=>46,'Utility'=>1.2,'LastShareTime'=>time()-rand(0,40)); 43 | $r['status']['devs'][]=array('Name'=>'Wut','ID'=>2,'Temperature'=>rand(20,35),'MHS5s'=>rand(6000,9000),'MHSav'=>rand(7000,8000),'LongPoll'=>'N','Getworks'=>1076,'Accepted'=>1324,'Rejected'=>1,'HardwareErrors'=>46,'Utility'=>1.2,'LastShareTime'=>time()-rand(0,300)); 44 | $r['status']['devs'][]=array('Name'=>'Wut','ID'=>4,'Temperature'=>rand(20,35),'MHS5s'=>0,'MHSav'=>0,'LongPoll'=>'N','Getworks'=>400,'Accepted'=>0,'Rejected'=>0,'HardwareErrors'=>0,'Utility'=>0,'LastShareTime'=>time()-rand(400,900)); 45 | $r['status']['devs'][]=array('Name'=>'More','ID'=>3,'Temperature'=>rand(20,35),'MHS5s'=>rand(500,1000),'MHSav'=>rand(600,800),'LongPoll'=>'N','Getworks'=>1076,'Accepted'=>1324,'Rejected'=>1,'HardwareErrors'=>46,'Utility'=>1.2,'LastShareTime'=>time()-rand(0,300)); 46 | $r['status']['pools'][]=array('POOL'=>5,'URL'=>'http://stratum.mining.eligius.st:3334','Status'=>'Alive','Priority'=>9,'LongPoll'=>'N','Getworks'=>10760,'Accepted'=>50430,'Rejected'=>60,'Discarded'=>21510,'Stale'=>0,'GetFailures'=>0,'RemoteFailures'=>0,'User'=>'1BveW6ZoZmx31uaXTEKJo5H9CK318feKKY','LastShareTime'=>1375501281,'Diff1Shares'=>20306,'ProxyType'=>'','Proxy'=>'','DifficultyAccepted'=>20142,'DifficultyRejected'=>24,'DifficultyStale'=>0,'LastShareDifficulty'=>4,'HasStratum'=>true,'StratumActive'=>true,'StratumURL'=>'stratum.mining.eligius.st','HasGBT'=>false,'BestShare'=>40657); 47 | } 48 | 49 | $devices = 0; 50 | $MHSav = 0; 51 | $MHS5s = 0; 52 | $Accepted = 0; 53 | $Rejected = 0; 54 | $HardwareErrors = 0; 55 | $Utility = 0; 56 | 57 | ChromePhp::log($r['status']); 58 | 59 | if(!empty($r['status']['devs'])){ 60 | foreach ($r['status']['devs'] as $id => $dev) { 61 | $devices += $dev['MHS5s']>0?1:0; // Only count hashing devices 62 | $MHS5s += $dev['MHS5s']; 63 | $MHSav += $dev['MHSav']; 64 | $Accepted += $dev['Accepted']; 65 | $Rejected += $dev['Rejected']; 66 | $HardwareErrors += $dev['HardwareErrors']; 67 | $Utility += $dev['Utility']; 68 | $r['status']['devs'][$id]['TotalShares']=$dev['Accepted']+$dev['Rejected']+$dev['HardwareErrors']; 69 | } 70 | } 71 | 72 | $r['status']['dtot']=array( 73 | 'devices'=>$devices, 74 | 'MHS5s'=>$MHS5s, 75 | 'MHSav'=>$MHSav, 76 | 'Accepted'=>$Accepted, 77 | 'Rejected'=>$Rejected, 78 | 'HardwareErrors'=>$HardwareErrors, 79 | 'Utility'=>$Utility, 80 | 'TotalShares'=>$Accepted+$Rejected+$HardwareErrors); 81 | 82 | // CPU intensive stuff 83 | if(!empty($_REQUEST['all'])){ 84 | $ret = sys_getloadavg(); 85 | $r['status']['pi']['load'] = $ret[2]; 86 | $ret = explode(' ', exec('cat /proc/uptime')); 87 | $r['status']['pi']['uptime'] = $ret[0]; 88 | $r['status']['pi']['temp'] = exec('cat /sys/class/thermal/thermal_zone0/temp')/1000; 89 | 90 | // What other interesting stuff is in summary? 91 | $summary=bfgminer('summary'); 92 | if(!empty($summary['data']['SUMMARY'][0]['Elapsed'])){ 93 | $r['status']['uptime'] = $summary['data']['SUMMARY'][0]['Elapsed']; 94 | } 95 | else{ 96 | $r['status']['uptime'] = 0; 97 | } 98 | } 99 | 100 | $r['status']['time'] = time(); 101 | 102 | //ChromePhp::log($r); 103 | 104 | echo json_encode($r); 105 | ?> -------------------------------------------------------------------------------- /var/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/favicon.ico -------------------------------------------------------------------------------- /var/www/img/bg-header1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/img/bg-header1.png -------------------------------------------------------------------------------- /var/www/img/favicon-1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/img/favicon-1.ico -------------------------------------------------------------------------------- /var/www/img/favicon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/img/favicon-1.png -------------------------------------------------------------------------------- /var/www/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/img/favicon.ico -------------------------------------------------------------------------------- /var/www/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/img/favicon.png -------------------------------------------------------------------------------- /var/www/img/scripta-logo-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/img/scripta-logo-152.png -------------------------------------------------------------------------------- /var/www/img/scripta-logo-ext-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/img/scripta-logo-ext-152.png -------------------------------------------------------------------------------- /var/www/inc/ChromePhp.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | class ChromePhp 25 | { 26 | /** 27 | * @var string 28 | */ 29 | const VERSION = '4.1.0'; 30 | 31 | /** 32 | * @var string 33 | */ 34 | const HEADER_NAME = 'X-ChromeLogger-Data'; 35 | 36 | /** 37 | * @var string 38 | */ 39 | const BACKTRACE_LEVEL = 'backtrace_level'; 40 | 41 | /** 42 | * @var string 43 | */ 44 | const LOG = 'log'; 45 | 46 | /** 47 | * @var string 48 | */ 49 | const WARN = 'warn'; 50 | 51 | /** 52 | * @var string 53 | */ 54 | const ERROR = 'error'; 55 | 56 | /** 57 | * @var string 58 | */ 59 | const GROUP = 'group'; 60 | 61 | /** 62 | * @var string 63 | */ 64 | const INFO = 'info'; 65 | 66 | /** 67 | * @var string 68 | */ 69 | const GROUP_END = 'groupEnd'; 70 | 71 | /** 72 | * @var string 73 | */ 74 | const GROUP_COLLAPSED = 'groupCollapsed'; 75 | 76 | /** 77 | * @var string 78 | */ 79 | const TABLE = 'table'; 80 | 81 | /** 82 | * @var string 83 | */ 84 | protected $_php_version; 85 | 86 | /** 87 | * @var int 88 | */ 89 | protected $_timestamp; 90 | 91 | /** 92 | * @var array 93 | */ 94 | protected $_json = array( 95 | 'version' => self::VERSION, 96 | 'columns' => array('log', 'backtrace', 'type'), 97 | 'rows' => array() 98 | ); 99 | 100 | /** 101 | * @var array 102 | */ 103 | protected $_backtraces = array(); 104 | 105 | /** 106 | * @var bool 107 | */ 108 | protected $_error_triggered = false; 109 | 110 | /** 111 | * @var array 112 | */ 113 | protected $_settings = array( 114 | self::BACKTRACE_LEVEL => 1 115 | ); 116 | 117 | /** 118 | * @var ChromePhp 119 | */ 120 | protected static $_instance; 121 | 122 | /** 123 | * Prevent recursion when working with objects referring to each other 124 | * 125 | * @var array 126 | */ 127 | protected $_processed = array(); 128 | 129 | /** 130 | * constructor 131 | */ 132 | private function __construct() 133 | { 134 | $this->_php_version = phpversion(); 135 | $this->_timestamp = $this->_php_version >= 5.1 ? $_SERVER['REQUEST_TIME'] : time(); 136 | $this->_json['request_uri'] = $_SERVER['REQUEST_URI']; 137 | } 138 | 139 | /** 140 | * gets instance of this class 141 | * 142 | * @return ChromePhp 143 | */ 144 | public static function getInstance() 145 | { 146 | if (self::$_instance === null) { 147 | self::$_instance = new self(); 148 | } 149 | return self::$_instance; 150 | } 151 | 152 | /** 153 | * logs a variable to the console 154 | * 155 | * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] 156 | * @return void 157 | */ 158 | public static function log() 159 | { 160 | $args = func_get_args(); 161 | return self::_log('', $args); 162 | } 163 | 164 | /** 165 | * logs a warning to the console 166 | * 167 | * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] 168 | * @return void 169 | */ 170 | public static function warn() 171 | { 172 | $args = func_get_args(); 173 | return self::_log(self::WARN, $args); 174 | } 175 | 176 | /** 177 | * logs an error to the console 178 | * 179 | * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] 180 | * @return void 181 | */ 182 | public static function error() 183 | { 184 | $args = func_get_args(); 185 | return self::_log(self::ERROR, $args); 186 | } 187 | 188 | /** 189 | * sends a group log 190 | * 191 | * @param string value 192 | */ 193 | public static function group() 194 | { 195 | $args = func_get_args(); 196 | return self::_log(self::GROUP, $args); 197 | } 198 | 199 | /** 200 | * sends an info log 201 | * 202 | * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] 203 | * @return void 204 | */ 205 | public static function info() 206 | { 207 | $args = func_get_args(); 208 | return self::_log(self::INFO, $args); 209 | } 210 | 211 | /** 212 | * sends a collapsed group log 213 | * 214 | * @param string value 215 | */ 216 | public static function groupCollapsed() 217 | { 218 | $args = func_get_args(); 219 | return self::_log(self::GROUP_COLLAPSED, $args); 220 | } 221 | 222 | /** 223 | * ends a group log 224 | * 225 | * @param string value 226 | */ 227 | public static function groupEnd() 228 | { 229 | $args = func_get_args(); 230 | return self::_log(self::GROUP_END, $args); 231 | } 232 | 233 | /** 234 | * sends a table log 235 | * 236 | * @param string value 237 | */ 238 | public static function table() 239 | { 240 | $args = func_get_args(); 241 | return self::_log(self::TABLE, $args); 242 | } 243 | 244 | /** 245 | * internal logging call 246 | * 247 | * @param string $type 248 | * @return void 249 | */ 250 | protected static function _log($type, array $args) 251 | { 252 | // nothing passed in, don't do anything 253 | if (count($args) == 0 && $type != self::GROUP_END) { 254 | return; 255 | } 256 | 257 | $logger = self::getInstance(); 258 | 259 | $logger->_processed = array(); 260 | 261 | $logs = array(); 262 | foreach ($args as $arg) { 263 | $logs[] = $logger->_convert($arg); 264 | } 265 | 266 | $backtrace = debug_backtrace(false); 267 | $level = $logger->getSetting(self::BACKTRACE_LEVEL); 268 | 269 | $backtrace_message = 'unknown'; 270 | if (isset($backtrace[$level]['file']) && isset($backtrace[$level]['line'])) { 271 | $backtrace_message = $backtrace[$level]['file'] . ' : ' . $backtrace[$level]['line']; 272 | } 273 | 274 | $logger->_addRow($logs, $backtrace_message, $type); 275 | } 276 | 277 | /** 278 | * converts an object to a better format for logging 279 | * 280 | * @param Object 281 | * @return array 282 | */ 283 | protected function _convert($object) 284 | { 285 | // if this isn't an object then just return it 286 | if (!is_object($object)) { 287 | return $object; 288 | } 289 | 290 | //Mark this object as processed so we don't convert it twice and it 291 | //Also avoid recursion when objects refer to each other 292 | $this->_processed[] = $object; 293 | 294 | $object_as_array = array(); 295 | 296 | // first add the class name 297 | $object_as_array['___class_name'] = get_class($object); 298 | 299 | // loop through object vars 300 | $object_vars = get_object_vars($object); 301 | foreach ($object_vars as $key => $value) { 302 | 303 | // same instance as parent object 304 | if ($value === $object || in_array($value, $this->_processed, true)) { 305 | $value = 'recursion - parent object [' . get_class($value) . ']'; 306 | } 307 | $object_as_array[$key] = $this->_convert($value); 308 | } 309 | 310 | $reflection = new ReflectionClass($object); 311 | 312 | // loop through the properties and add those 313 | foreach ($reflection->getProperties() as $property) { 314 | 315 | // if one of these properties was already added above then ignore it 316 | if (array_key_exists($property->getName(), $object_vars)) { 317 | continue; 318 | } 319 | $type = $this->_getPropertyKey($property); 320 | 321 | if ($this->_php_version >= 5.3) { 322 | $property->setAccessible(true); 323 | } 324 | 325 | try { 326 | $value = $property->getValue($object); 327 | } catch (ReflectionException $e) { 328 | $value = 'only PHP 5.3 can access private/protected properties'; 329 | } 330 | 331 | // same instance as parent object 332 | if ($value === $object || in_array($value, $this->_processed, true)) { 333 | $value = 'recursion - parent object [' . get_class($value) . ']'; 334 | } 335 | 336 | $object_as_array[$type] = $this->_convert($value); 337 | } 338 | return $object_as_array; 339 | } 340 | 341 | /** 342 | * takes a reflection property and returns a nicely formatted key of the property name 343 | * 344 | * @param ReflectionProperty 345 | * @return string 346 | */ 347 | protected function _getPropertyKey(ReflectionProperty $property) 348 | { 349 | $static = $property->isStatic() ? ' static' : ''; 350 | if ($property->isPublic()) { 351 | return 'public' . $static . ' ' . $property->getName(); 352 | } 353 | 354 | if ($property->isProtected()) { 355 | return 'protected' . $static . ' ' . $property->getName(); 356 | } 357 | 358 | if ($property->isPrivate()) { 359 | return 'private' . $static . ' ' . $property->getName(); 360 | } 361 | } 362 | 363 | /** 364 | * adds a value to the data array 365 | * 366 | * @var mixed 367 | * @return void 368 | */ 369 | protected function _addRow(array $logs, $backtrace, $type) 370 | { 371 | // if this is logged on the same line for example in a loop, set it to null to save space 372 | if (in_array($backtrace, $this->_backtraces)) { 373 | $backtrace = null; 374 | } 375 | 376 | // for group, groupEnd, and groupCollapsed 377 | // take out the backtrace since it is not useful 378 | if ($type == self::GROUP || $type == self::GROUP_END || $type == self::GROUP_COLLAPSED) { 379 | $backtrace = null; 380 | } 381 | 382 | if ($backtrace !== null) { 383 | $this->_backtraces[] = $backtrace; 384 | } 385 | 386 | $row = array($logs, $backtrace, $type); 387 | 388 | $this->_json['rows'][] = $row; 389 | $this->_writeHeader($this->_json); 390 | } 391 | 392 | protected function _writeHeader($data) 393 | { 394 | header(self::HEADER_NAME . ': ' . $this->_encode($data)); 395 | } 396 | 397 | /** 398 | * encodes the data to be sent along with the request 399 | * 400 | * @param array $data 401 | * @return string 402 | */ 403 | protected function _encode($data) 404 | { 405 | return base64_encode(utf8_encode(json_encode($data))); 406 | } 407 | 408 | /** 409 | * adds a setting 410 | * 411 | * @param string key 412 | * @param mixed value 413 | * @return void 414 | */ 415 | public function addSetting($key, $value) 416 | { 417 | $this->_settings[$key] = $value; 418 | } 419 | 420 | /** 421 | * add ability to set multiple settings in one call 422 | * 423 | * @param array $settings 424 | * @return void 425 | */ 426 | public function addSettings(array $settings) 427 | { 428 | foreach ($settings as $key => $value) { 429 | $this->addSetting($key, $value); 430 | } 431 | } 432 | 433 | /** 434 | * gets a setting 435 | * 436 | * @param string key 437 | * @return mixed 438 | */ 439 | public function getSetting($key) 440 | { 441 | if (!isset($this->_settings[$key])) { 442 | return null; 443 | } 444 | return $this->_settings[$key]; 445 | } 446 | } 447 | -------------------------------------------------------------------------------- /var/www/inc/backup.inc.php: -------------------------------------------------------------------------------- 1 | 'danger', 'text' => 'Source file is not readable'); 57 | } 58 | elseif (is_file($src)&&is_dir($dst) || is_dir($src)&&is_file($dst)) { 59 | $r['info'][]=array('type' => 'danger', 'text' => 'File and folder mixup'); 60 | } 61 | elseif (is_file($dst)) { 62 | $r['info'][]=array('type' => 'danger', 'text' => 'Destination file already exists'); 63 | } 64 | 65 | // Copy it already! 66 | if (@is_file($src)) { 67 | $r['type']='file'; 68 | if (!@copy($src, $dst)) { 69 | $r['files'][0]=array('file'=>pathinfo($dst,PATHINFO_BASENAME),'success'=>false); 70 | } 71 | else{ 72 | $r['success']=true; 73 | $r['files'][0]=array('file'=>pathinfo($dst,PATHINFO_BASENAME),'success'=>true); 74 | } 75 | } 76 | elseif (@is_dir($src)) { 77 | $r['type']='dir'; 78 | if (recurse_copy($src, $dst)) { 79 | $r['success']=true; 80 | } 81 | } 82 | 83 | return $r; 84 | } 85 | 86 | // Copy a folder recursively 87 | function recurse_copy($src,$dst,$level=3) { 88 | $success=true; 89 | if($level==0) return $success; 90 | global $r; 91 | $dir = opendir($src); 92 | @mkdir($dst); 93 | while(false !== ( $file = readdir($dir))) { 94 | if (( $file != '.' ) && ( $file != '..' )) { 95 | if ( is_dir($src . '/' . $file) ) { 96 | $c=recurse_copy($src . '/' . $file,$dst . '/' . $file,$level-1); 97 | } 98 | else { 99 | $c=@copy($src . '/' . $file,$dst . '/' . $file); 100 | $r['files'][]=array('file'=>pathinfo($dst,PATHINFO_BASENAME),'success'=>$c); 101 | } 102 | $success=$success&&$c; 103 | } 104 | } 105 | closedir($dir); 106 | return $success; 107 | } 108 | ?> 109 | -------------------------------------------------------------------------------- /var/www/inc/bfgminer.inc.php: -------------------------------------------------------------------------------- 1 | 'error', 'text' => 'Miner: '.$errno.' '.$errorMessage); 38 | } 39 | // Socket success 40 | else{ 41 | fwrite($client, json_encode($c)); 42 | $response = stream_get_contents($client); 43 | fclose($client); 44 | 45 | // Cleanup json 46 | $response = preg_replace('/[^[:alnum:][:punct:]]/','',$response); 47 | 48 | // Add api response 49 | $r['data'] = json_decode($response, true); 50 | $r['info'][]=array('type' => 'info', 'text' => 'Miner: '.$command); 51 | } 52 | 53 | return $r; 54 | } 55 | ?> 56 | -------------------------------------------------------------------------------- /var/www/inc/functions.inc.php: -------------------------------------------------------------------------------- 1 | $settings['alertSmtp'], 15 | 'debug' => false, 16 | 'auth' => true, 17 | 'username' => $settings['alertSmtpUser'], 18 | 'password' => $settings['alertSmtpPwd'], 19 | 'port' => $settings['alertSmtpPort'], 20 | 21 | ); 22 | 23 | //$settings['alertDevice'] 24 | 25 | $mail = Mail::factory('smtp', $mailSettings ); 26 | 27 | $headers = array('From'=>$settings['alertEmail'], 'Subject'=>$subject); 28 | $esito = $mail->send($settings['alertEmail'], $headers, $body); 29 | if (PEAR::isError($esito)) { print($esito->getMessage());}else{print "end";} 30 | } 31 | ?> -------------------------------------------------------------------------------- /var/www/inc/host.inc.php: -------------------------------------------------------------------------------- 1 | Reboot 12 | * 1 ---> Shutdown 13 | */ 14 | 15 | function hostHardCtl($op,$pass){ 16 | openlog("myScriptLog", LOG_PID | LOG_PERROR, LOG_LOCAL0); 17 | syslog(LOG_WARNING, "Attempting to exec hostHardCtl"); 18 | 19 | switch ($op) { 20 | case 0: 21 | $cmd = '"/sbin/shutdown -r now"'; 22 | break; 23 | case 1: 24 | $cmd = '"/sbin/shutdown -h now"'; 25 | break; 26 | default: 27 | syslog(LOG_WARNING, "unknown command"); 28 | break; 29 | } 30 | 31 | //$cmd = '"ls -la /root"'; 32 | 33 | $cases = array ( 34 | array (0 => "Password: ", 1 => "PASSWORD") 35 | ); 36 | 37 | $full_cmd = "su -c ".$cmd; 38 | syslog(LOG_WARNING, "execute: ". $full_cmd); 39 | $stream = expect_popen($full_cmd); 40 | $ret = expect_expectl($stream, $cases); 41 | 42 | switch ($ret) { 43 | case "PASSWORD": 44 | fwrite ($stream, $pass."\n"); 45 | syslog(LOG_WARNING, "pwd: ". $pass); 46 | break; 47 | case EXP_TIMEOUT: 48 | syslog(LOG_WARNING, "EXP_TIMEOUT"); 49 | return false; 50 | break; 51 | case EXP_EOF: 52 | syslog(LOG_WARNING, "EXP_EOF"); 53 | return false; 54 | break; 55 | default: 56 | syslog(LOG_WARNING, "EXP_TIMEOUT"); 57 | return false; 58 | break; 59 | } 60 | 61 | $out = ''; 62 | while ($line = fgets($stream)) { 63 | $out .= $line; 64 | syslog(LOG_WARNING, "ret: ". $line); 65 | } 66 | fclose ($stream); 67 | closelog(); 68 | return $out; 69 | } 70 | ?> 71 | 72 | -------------------------------------------------------------------------------- /var/www/inc/kitten.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/inc/kitten.mp3 -------------------------------------------------------------------------------- /var/www/inc/kitten.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptamining/scripta/6c612e9a6df050688921ab14ac330dfabf27c9de/var/www/inc/kitten.wav -------------------------------------------------------------------------------- /var/www/inc/miner.inc.php: -------------------------------------------------------------------------------- 1 | $command, 7 | 'parameter' => $parameter 8 | ); 9 | 10 | $jsonCmd = json_encode($command); 11 | 12 | $host = '127.0.0.1'; 13 | $port = 4028; 14 | 15 | $client = @stream_socket_client('tcp://'.$host.':'.$port, $errno, $errorMessage); 16 | 17 | if ($client === false) { 18 | return false; 19 | } 20 | fwrite($client, $jsonCmd); 21 | $response = stream_get_contents($client); 22 | fclose($client); 23 | $response = preg_replace('/[^[:alnum:][:punct:]]/','',$response); 24 | $response = json_decode($response, true); 25 | return $response; 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /var/www/inc/settings.inc.php: -------------------------------------------------------------------------------- 1 | 'cli') { 4 | header('Location: https://' . $_SERVER["SERVER_NAME"] . $_SERVER['REQUEST_URI']); 5 | } 6 | 7 | $settings = json_decode(@file_get_contents('/opt/scripta/etc/scripta.conf'), true); 8 | $settings['donateEnable'] = true; 9 | 10 | 11 | 12 | if(isset($settings['userTimezone'])){ 13 | $timezone = $settings['userTimezone']; 14 | ini_set( 'date.timezone', $timezone ); 15 | putenv('TZ=' . $timezone); 16 | date_default_timezone_set($timezone); 17 | } 18 | 19 | 20 | 21 | 22 | function writeSettings($settings, $file = 'scripta.conf') { 23 | // Call this when you want settings to be saved with writeSettings($settings); 24 | // can be used to save to an alternat file name with writeSettings($settings, 'OtherFileName.conf); 25 | 26 | file_put_contents("/opt/scripta/etc/" . $file, json_encode($settings, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK)); 27 | } 28 | 29 | ?> 30 | -------------------------------------------------------------------------------- /var/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scripta 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 49 | 50 |
51 |
52 |

53 | Loading angular.js the first time might take some seconds... Hang tight! 54 |

55 |
56 |
57 | 58 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /var/www/index.lighttpd.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Welcome page 6 | 19 | 20 | 21 |
22 | 26 |
27 |

You should replace this page with your own web pages as soon as possible.

28 | Unless you changed its configuration, your new server is configured as follows: 29 | 37 |

About this page

38 |

39 | This is a placeholder page installed by the Debian release of the Lighttpd server package. 40 |

41 |

42 | This computer has installed the Debian GNU/Linux operating system, but it has nothing to do with the Debian Project. Please do not contact the Debian Project about it. 43 |

44 |

45 | If you find a bug in this Lighttpd package, or in Lighttpd itself, please file a bug report on it. Instructions on doing this, and the list of known bugs of this package, can be found in the 46 | Debian Bug Tracking System. 47 |

48 |

49 | Valid XHTML 1.0 Transitional 52 |

53 |
54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /var/www/index.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | Scr|pta 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 68 | 69 |
70 |
71 |

72 | Loading angular.js the first time might take some seconds... Hang tight! 73 |

74 |
75 |
76 | 77 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /var/www/info.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /var/www/js/alertify.min.js: -------------------------------------------------------------------------------- 1 | /*! alertify 0.4.0rc1 (Fabien Doiron) | MIT */ 2 | (function(t,e,n){var i=function(){var t,n,i;return n=function(){this.on=function(t,e,n){t.addEventListener(e,n,!1)},this.off=function(t,e,n){t.removeEventListener(e,n,!1)}},i=function(){this.on=function(t,e,n){t.attachEvent("on"+e,n)},this.off=function(t,e,n){t.detachEvent("on"+e,n)}},t={_version:"0.4.0",_prefix:"alertify",get:function(t){return e.getElementById(t)},on:function(t,e,r){"function"==typeof t.addEventListener?(t.addEventListener(e,r,!1),n.call(this)):t.attachEvent&&(t.attachEvent("on"+e,r),i.call(this))},off:function(t,e,r){"function"==typeof t.removeEventListener?(t.removeEventListener(e,r,!1),n.call(this)):t.detachEvent&&(t.detachEvent("on"+e,r),i.call(this))}}}(),r=function(){var t=function(){};return t.prototype=i,t=new t}(),o=function(){var t,e;return t=function(t,e,i){var r=!1;return r=i&&e===n?!0:"object"===t?"object"==typeof e&&!(e instanceof Array):typeof e===t},e={messages:{invalidArguments:"Invalid arguments"},isFunction:function(e,n){return t("function",e,n)},isNumber:function(e,n){return t("number",e,n)},isObject:function(e,n){return t("object",e,n)},isString:function(e,n){return t("string",e,n)}}}(),s=function(){var t,i={};return t=function(t,e){var i;if(!o.isObject(t)||!o.isObject(e,!0))throw Error(o.messages.invalidArguments);if(e!==n){if(e.attributes)for(i in e.attributes)e.attributes.hasOwnProperty(i)&&t.setAttribute(i,e.attributes[i]);e.classes&&(t.className=e.classes)}return t},i={create:function(n,i){var r;if(!o.isString(n)||!o.isObject(i,!0))throw Error(o.messages.invalidArguments);return r=e.createElement(n),r=t(r,i)},ready:function(t){if(!o.isObject(t))throw Error(o.messages.invalidArguments);t&&null!==t.scrollTop||this.ready()}}}(),a=function(){var t;return t=function(){var t,e,i=!1,r=s.create("fakeelement"),o={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"otransitionend",transition:"transitionend"};for(t in o)if(r.style[t]!==n){e=o[t],i=!0;break}return{type:e,supported:i}},t()}(),c=function(){var t={ENTER:13,ESC:27,SPACE:32};return t}(),l=function(){var t=function(){var t,i,l,u,f,p,h,d,y,b,v,m,g,k,E,w={},F={},N=!1,S=[],A={},C=r._prefix+"-dialog",x=r._prefix+"-cover",j=C+" is-"+C+"-showing",O=C+" is-"+C+"-hidden",T=x+" is-"+x+"-showing",L=x+" is-"+x+"-hidden";return A={buttons:{holder:'',submit:'',ok:'',cancel:''},input:'
',message:'

{{message}}

',log:'
{{message}}
'},l=function(t){d=function(e){var i="";return e.preventDefault!==n&&e.preventDefault(),g(),f(),w.input&&(i=w.input.value),"function"==typeof t.accept&&(w.input?t.accept(i):t.accept()),!1},h=function(e){return e.preventDefault!==n&&e.preventDefault(),g(),f(),"function"==typeof t.deny&&t.deny(),!1},v=function(t){var e=t.keyCode;e!==c.SPACE||w.input||d(t),e===c.ESC&&w.cancel&&h(t)},y=function(){w.input?w.input.focus():w.cancel?w.cancel.focus():w.ok.focus()},r.on(w.reset,"focus",y),w.ok&&r.on(w.ok,"click",d),w.cancel&&r.on(w.cancel,"click",h),r.on(e.body,"keyup",v),w.form&&r.on(w.form,"submit",d),a.supported||k()},i=function(t,e){return F.buttonReverse?e+t:t+e},u=function(t){var e="",n=t.type,r=t.message;switch(e+='
',"none"===F.buttonFocus&&(e+=''),"prompt"===n&&(e+='
'),e+='
',e+=A.message.replace("{{message}}",r),"prompt"===n&&(e+=A.input),e+=A.buttons.holder,e+="
","prompt"===n&&(e+="
"),e+='Reset Focus',e+="
",n){case"confirm":e=e.replace("{{buttons}}",i(A.buttons.cancel,A.buttons.ok)),e=e.replace("{{ok}}",F.labels.ok).replace("{{cancel}}",F.labels.cancel);break;case"prompt":e=e.replace("{{buttons}}",i(A.buttons.cancel,A.buttons.submit)),e=e.replace("{{ok}}",F.labels.ok).replace("{{cancel}}",F.labels.cancel);break;case"alert":e=e.replace("{{buttons}}",A.buttons.ok),e=e.replace("{{ok}}",F.labels.ok)}return e},f=function(){var e;S.splice(0,1),S.length>0?m(!0):(N=!1,e=function(t){t.stopPropagation(),r.off(this,a.type,e)},a.supported?(r.on(F.el,a.type,e),F.el.className=O):F.el.className=O,F.cover.className=L,t.focus())},p=function(){var t=s.create("div",{classes:L}),n=s.create("section",{classes:O});return e.body.appendChild(t),e.body.appendChild(n),s.ready(t),s.ready(n),F.cover=t,n},m=function(t){var e,i=S[0];N=!0,e=function(t){t.stopPropagation(),k(),r.off(this,a.type,e)},a.supported&&!t&&r.on(F.el,a.type,e),F.el.innerHTML=u(i),F.cover.className=T,F.el.className=j,w.reset=r.get("alertify-resetFocus"),w.ok=r.get("alertify-ok")||n,w.cancel=r.get("alertify-cancel")||n,w.focus="cancel"===F.buttonFocus&&w.cancel?w.cancel:"none"===F.buttonFocus?r.get("alertify-noneFocus"):w.ok,w.input=r.get("alertify-text")||n,w.form=r.get("alertify-form")||n,"string"==typeof i.placeholder&&""!==i.placeholder&&(w.input.value=i.placeholder),t&&k(),l(i)},g=function(){r.off(e.body,"keyup",v),r.off(w.reset,"focus",y),w.input&&r.off(w.form,"submit",b),w.ok&&r.off(w.ok,"click",d),w.cancel&&r.off(w.cancel,"click",h)},k=function(){w.input?(w.input.focus(),w.input.select()):w.focus.focus()},E=function(n,i,r,s,a){if(!(o.isString(n)&&o.isString(i)&&o.isFunction(r,!0)&&o.isFunction(s,!0)&&o.isString(a,!0)))throw Error(o.messages.invalidArguments);F.el=F.el||p(),t=e.activeElement,S.push({type:n,message:i,accept:r,deny:s,placeholder:a}),N||m()},{buttonFocus:"ok",buttonReverse:!1,cover:n,el:n,labels:{ok:"OK",cancel:"Cancel"},alert:function(t,e){return F=this,E("alert",t,e),this},confirm:function(t,e,n){return F=this,E("confirm",t,e,n),this},prompt:function(t,e,n,i){return F=this,E("prompt",t,e,n,i),this}}};return new t}(),u=function(){var t,e,i,c,l=r._prefix+"-log",u=l+" is-"+l+"-showing",f=l+" is-"+l+"-hidden";return t=function(t,e,i,r){if(!(o.isObject(t)&&o.isString(e)&&o.isString(i)&&o.isNumber(r,!0)))throw Error(o.messages.invalidArguments);this.delay=r!==n?r:5e3,this.msg=i,this.parent=t,this.type=e,this.create(),this.show()},e=function(t){t.stopPropagation(),this.el!==n&&(r.off(this.el,a.type,this.fn),i.call(this))},i=function(){this.parent.removeChild(this.el),delete this.el},c=function(){var t=this;0!==this.delay&&setTimeout(function(){t.close()},this.delay)},t.prototype.close=function(){var t=this;this.el!==n&&this.el.parentNode===this.parent&&(a.supported?(this.fn=function(n){e.call(t,n)},r.on(this.el,a.type,this.fn),this.el.className=f+" "+l+"-"+this.type):i.call(this))},t.prototype.create=function(){if(this.el===n){var t=s.create("article",{classes:f+" "+l+"-"+this.type});t.innerHTML=this.msg,this.parent.appendChild(t),s.ready(t),this.el=t}},t.prototype.show=function(){var t=this;this.el!==n&&(r.on(this.el,"click",function(){t.close()}),this.el.className=u+" "+l+"-"+this.type,c.call(this))},t}(),f=function(){var t,i,a,c;return t=function(){var t=s.create("section",{classes:r._prefix+"-logs"});return e.body.appendChild(t),s.ready(t),t},i=function(e,n,i){return a(e,n,i),this.el=this.el||t(),new u(this.el,e,n,i)},a=function(t,e,n){if(!o.isString(t)||!o.isString(e)||!o.isNumber(n,!0))throw Error(o.messages.invalidArguments)},c={delay:5e3,el:n,create:function(t,e,n){return i.call(this,t,e,n)},error:function(t,e){return i.call(this,"error",t,e)},info:function(t,e){return i.call(this,"info",t,e)},success:function(t,e){return i.call(this,"success",t,e)}}}();r.dialog=l,r.log=f,window.Alertify=r})(this,document); -------------------------------------------------------------------------------- /var/www/lighttpd.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCp4yeDMiOFxkLv 3 | 78H/EQE0ZJFA9qtkCaOPB9TnYT98gBm75QIAmncQoPlpZvIEFnYfvSiVow2THS4b 4 | vz+z7F2qSCqBVin32QKKLMDkVKFUdQ3ffGUyMQYPyn0EnDs8x46BATtHCCO272Ti 5 | 7fAEorP+sBB452o132tOFvV8iSGxgYjUTarV6DT3b8xHdOqmcvtH95C4OF+4237C 6 | WSX+RF/XwuOr3y19bY/NWg9TqLPlsB5eZfZTXRoHmkCqU10t2NJISXQP6g5rt3FO 7 | G/pGSsKfg2RSZrqr1EmR8Bp/2r8Him3XdtsoI343sRv0AA5YPwi0UEB2HWt3lHO/ 8 | p/v9ychXAgMBAAECggEAPOWUEE80tIsxC1jiLVAnImS6PJMvNJjP7EFea+JMI5C3 9 | qMaaRSUZcPiC7ulb72MtzIq9tYXRI97d3ExdxV0A5j0gH2SHfrRnWKhaLH65pdCf 10 | vHCWxbsU9SwcTD7EbTELP+r1GK0uQDDn9QBdfQvlgXITNYOeatk/WaqZLJ7rWPkE 11 | VHVUN+FU094CzeIclX5Z/bt/HnW442ypyEyeXyJAMcCx8nMMKth3pKeBMsuzKJzd 12 | qg1KCMiuJfY/06pVUEqBtYfpe0SXqIZc1qTTFHYdQvIOMjXTEq/TbVuZhXOHMHo9 13 | D8nP2E3/tjPHhACFZNayhLt1GNjbfJIXMfZrEmbuQQKBgQDRKYjyT1c+ZnZF+yVh 14 | K2P++VbWYQnEbbF0+LTR3Um5uRTXXd1wGGx8HJWmyrQG8wpzhCXDSm1WkG7BAwaq 15 | 7f+08f9ReB99ed0LejmdFxCY9zU2iS/wQNXufGHB2QlHHyvm4WFu2lM3NzDBdZgD 16 | 2ltuoZJVp2wCI2vmQQzloiIHTwKBgQDP7iOxzLpoq4iDEtmZ3+RniTIWxav6ACx3 17 | US2xaaK8kXwCxJo69Gf20niWGrVn/HRX06L4xumsNCAPCp232AU0hrMb450zkHPc 18 | YS7B3JzJW2vZyVg1r4co2z6Avgo29aX/M7sye0HTyxEB913IQ8iVXy0MzcGffqQL 19 | NJ3/HbFseQKBgFAqGSC1o/x4jNAZh6QMW1D4A346xuGQITlxsOvWYlFaTFCW2y4B 20 | TmLrGbhJbGJVeCX5+fc1aV6KEMjM/hs5CI4zSeXRolAXCs9BUx+QHX5jEPQL9GGi 21 | l9vFtDn1kwa9PbhJnWw9JTO+ZWNgTJj9cZmfN1S4zD6tkMc5G1ZPo7clAoGBAM7I 22 | 7gasq9XcgW6ZGH7HAsdU0dOD0nxWH+KpgN+nRohxxvqZuyhWV+5HclUVSsOXdbzC 23 | ZJk0eL8hN6C91gw3cTXDn+xkeLoHNrI8k9uIIwS9PozgiDEb1zbykz5FwLLXqbYb 24 | JFgX7GdM1CU4dLPtdVXXyV2qYpzTvSDHuzkztndBAoGBAKf90jw5ECPrQrvcV3Cq 25 | I0UiAmwZVHM81TfAGlVSvlCfTKUH5U9g7/fNmJ2ERlgpcKu9Kb2W3fzIbWqaIQYu 26 | BPY6OK7Fj4cjJAIMFsMQhrwNuAWDRCBFCzJpTgEm3M1bVG32jyraqH9AbsUXRIeq 27 | GWYVaV6udf1LQ/OYN2eY1IBY 28 | -----END PRIVATE KEY----- 29 | -----BEGIN CERTIFICATE----- 30 | MIIDXTCCAkWgAwIBAgIJAP3hS6UzK4NiMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV 31 | BAYTAklUMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX 32 | aWRnaXRzIFB0eSBMdGQwHhcNMTQwMjIxMDc1OTM2WhcNMTUwMjIxMDc1OTM2WjBF 33 | MQswCQYDVQQGEwJJVDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 34 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 35 | CgKCAQEAqeMngzIjhcZC7+/B/xEBNGSRQParZAmjjwfU52E/fIAZu+UCAJp3EKD5 36 | aWbyBBZ2H70olaMNkx0uG78/s+xdqkgqgVYp99kCiizA5FShVHUN33xlMjEGD8p9 37 | BJw7PMeOgQE7Rwgjtu9k4u3wBKKz/rAQeOdqNd9rThb1fIkhsYGI1E2q1eg092/M 38 | R3TqpnL7R/eQuDhfuNt+wlkl/kRf18Ljq98tfW2PzVoPU6iz5bAeXmX2U10aB5pA 39 | qlNdLdjSSEl0D+oOa7dxThv6RkrCn4NkUma6q9RJkfAaf9q/B4pt13bbKCN+N7Eb 40 | 9AAOWD8ItFBAdh1rd5Rzv6f7/cnIVwIDAQABo1AwTjAdBgNVHQ4EFgQUmq4ILR/Q 41 | TGT5Jm3Yg+uiwSn07GkwHwYDVR0jBBgwFoAUmq4ILR/QTGT5Jm3Yg+uiwSn07Gkw 42 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAJPhEA9JNwFNIC3EHgXve 43 | +KXC5A8XZWFJDBZlQlbtkZ/xjXE/Uw7wdE/cHqAJtK5UTO7cc48lIWiXb6h2aORl 44 | qpWbYCWVTYxgA7WrdvIFNLlCcrCO8OcTuJl/ra5Y5nzPD0DM+Se4riosTEmQozYA 45 | aUrlIDINWdmPULlBlExmKBcMv+yazi3vAIJYHwKdzPZyt3O+vBl+FFAVMD5SpiOq 46 | P+1NPEQz6DS/uIG80/HF6Q2WoB5ZKiQeHQGZPLZI5WMLdNdeU3lYX+SKAm04NkA5 47 | BoWG5iOVchYF9+t8AexKeLCnJPoNiyz6LomlpzHIToVvf2qlNqh3rwRxuknF+Ji9 48 | zg== 49 | -----END CERTIFICATE----- 50 | -------------------------------------------------------------------------------- /var/www/login.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | Scr|pta 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 48 | 49 |
50 |


51 |

52 |

53 |
54 |
55 | 56 |
57 | 58 |
59 |
60 | 61 | 62 |
63 |
64 |
65 |
66 |

67 |
68 | 69 | 70 | 79 | 80 | 81 | 82 | 83 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /var/www/ng/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (window.location.protocol != "https:") 4 | window.location.href = "https:" + window.location.href.substring(window.location.protocol.length); 5 | 6 | // Declare app level module which depends on filters, and services 7 | angular.module('Scripta', ['Scripta.filters', 'Scripta.services', 'Scripta.directives', 'Scripta.controllers']) 8 | .config(['$routeProvider', function($routeProvider) { 9 | $routeProvider.when('/status', {templateUrl: 'partials/status.html', controller: 'CtrlStatus'}); 10 | $routeProvider.when('/miner', {templateUrl: 'partials/miner.html', controller: 'CtrlMiner'}); 11 | $routeProvider.when('/settings', {templateUrl: 'partials/settings.html', controller: 'CtrlSettings'}); 12 | $routeProvider.when('/backup', {templateUrl: 'partials/backup.html', controller: 'CtrlBackup'}); 13 | 14 | $routeProvider.otherwise({redirectTo: '/status'}); 15 | }]); 16 | -------------------------------------------------------------------------------- /var/www/ng/controllers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Controllers */ 4 | 5 | angular.module('Scripta.controllers', []) 6 | 7 | 8 | // Main: stores status 9 | .controller('CtrlMain', function($scope,$http,$timeout,$window,$filter) { 10 | // Settings 11 | $scope.settings={}; 12 | $scope.settingsMaster={}; 13 | // Pools 14 | $scope.pools={}; 15 | $scope.options={}; 16 | // Status 17 | $scope.status={}; 18 | $scope.status.extra=true; // Request extra data 19 | $scope.title="Miner interface initialization"; 20 | // Refresh 21 | $scope.intervalAuto = true; // Automatically adjust interval 22 | $scope.intervalMax = 20; // Default refresh rate 23 | // Live graph 24 | $scope.live=[]; 25 | $scope.settings.liveMax=50; 26 | $scope.upLast=0; 27 | $scope.downLast=0; 28 | // Alerts 29 | Alertify.log.delay=10000; 30 | 31 | // Sync settings 32 | // Note: not possible to remove settings! 33 | $scope.sync = function(action,data,alert) { 34 | action = action || 'settings'; 35 | data = data || 'load'; 36 | $http.get('f_settings.php?'+action+'='+angular.toJson(data)).success(function(d){ 37 | if(d.info){ 38 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 39 | } 40 | if(action=='settings'){ 41 | $scope.settings=angular.copy(d['data']); 42 | } 43 | else if(action=='pools'){ 44 | $scope.pools=d['data']; 45 | } 46 | else if(action=='options'){ 47 | $scope.options=d['data']; 48 | } 49 | else if(action=='timezone'){ 50 | $scope.settings.date=d.data.date; 51 | } 52 | }); 53 | } 54 | $scope.syncDelay = function(ms,action,data,alert) { 55 | action = action || 'settings'; 56 | data = data || false; 57 | ms = ms || 1000; 58 | var syncNow = function(){ 59 | $scope.sync(action,data,alert); 60 | } 61 | return $timeout(syncNow, ms); 62 | } 63 | 64 | // Sync settings 65 | $scope.sync('settings') 66 | 67 | // Get status and save in scope 68 | $scope.tick = function(once,all) { 69 | $http.get('f_status.php?'+($scope.settings.userDeveloper?'dev=1&':'')+(all||$scope.status.extra?'all=1':'')).success(function(d){ 70 | if(d.info){ 71 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 72 | } 73 | // Update status 74 | angular.forEach(d.status, function(v,k) {$scope.status[k]=v;}); 75 | // Title 76 | $scope.title=$scope.status.minerDown?'Miner DOWN -':'['+$filter('mhs')($scope.status.dtot.MHS5s)+'h] ['+$scope.status.dtot.devices+' dev]'; 77 | // Live Graphs 78 | $scope.live.push([Date.now(),1000000*$scope.status.dtot.MHS5s]); 79 | // Stop requesting extra data 80 | $scope.status.extra=false; 81 | }) 82 | .error(function(){ 83 | // Title 84 | $scope.title='Scripta DOWN -'; 85 | // Live Graphs 86 | $scope.live.push([Date.now(),0]); 87 | }) 88 | .then(function(){ 89 | if($scope.live.length>$scope.settings.liveMax){ 90 | $scope.live=$scope.live.slice(-$scope.settings.liveMax); 91 | } 92 | // Manage interval 93 | if($scope.interval<$scope.intervalMax){ 94 | $scope.interval++; 95 | } 96 | }); 97 | } 98 | 99 | $scope.intervalSet = function(num) { 100 | if(num<2){ 101 | $scope.intervalAuto=!$scope.intervalAuto; 102 | if($scope.intervalAuto) $scope.interval=1; 103 | } 104 | else{ 105 | $scope.intervalMax=num; 106 | $scope.interval=num; 107 | } 108 | }; 109 | var count = function () { 110 | $timeout(count, 1000); 111 | if($scope.counter>0){ 112 | $scope.counter--; 113 | } 114 | else{ 115 | $scope.counter=$scope.interval-1; 116 | $scope.tick(); 117 | } 118 | }; 119 | count(); 120 | 121 | $scope.$watch('title', function(b,a) { 122 | $window.document.title=b+' Scripta'; 123 | }); 124 | 125 | $scope.$watch('intervalAuto', function(b,a) { 126 | Alertify.log.info('Automatic refresh rate '+(b?'en':'dis')+'abled'); 127 | }); 128 | 129 | $scope.$watch('intervalMax', function(b,a) { 130 | Alertify.log.info('Refresh rate is now '+b); 131 | if($scope.counter>b){ 132 | $scope.counter=0; 133 | } 134 | $scope.status.extra=true; 135 | }); 136 | 137 | $scope.$watch('status.minerDown', function(b,a) { 138 | if(b){ 139 | $scope.upLast=Date.now(); 140 | Alertify.log.error('Miner seems down'); 141 | } 142 | else{ 143 | $scope.downLast=Date.now(); 144 | Alertify.log.success('Miner is up!'); 145 | } 146 | $scope.interval=1; 147 | $scope.counter=0; 148 | $scope.status.extra=true; 149 | }); 150 | }) 151 | 152 | 153 | .controller('CtrlStatus', function($scope,$http) { 154 | $scope.status.extra=true; 155 | $scope.num=0; 156 | 157 | $scope.graphUpdate = function() { 158 | $http.get('f_graph.php').success(function(d){ 159 | 160 | if(d){ 161 | Alertify.log.success("Graphs updated"); 162 | } 163 | else{ 164 | Alertify.log.error("Update graph ended in error"); 165 | } 166 | $scope.num++; 167 | }).error(function(){ 168 | Alertify.log.error("Update graph ended in error: https enabled?"); 169 | }); 170 | } 171 | }) 172 | 173 | 174 | .controller('CtrlMiner', function($scope,$http,$timeout) { 175 | $scope.status.extra=true; 176 | $scope.sync('pools'); 177 | $scope.sync('options'); 178 | 179 | $scope.minerCompat = function(command,parameter) { 180 | $http.get('f_minercompat.php').success(function(d){ 181 | if(d.info){ 182 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 183 | } 184 | if(d.data.pools){ 185 | $scope.pools=d.data.pools; 186 | } 187 | if(d.data.options){ 188 | $scope.options=d.data.options; 189 | } 190 | }); 191 | } 192 | 193 | $scope.bfgminer = function(command,parameter) { 194 | $scope.tick(); 195 | 196 | var execute = function(){ 197 | $http.get('f_miner.php?command='+(command || 'summary')+'¶meter='+parameter).success(function(d){ 198 | if(d.info){ 199 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 200 | } 201 | $scope.tick(); 202 | }); 203 | } 204 | $timeout(execute, 1000); 205 | }; 206 | 207 | $scope.bfgminerHardCtl = function(command) { 208 | $scope.tick(); 209 | 210 | var execute = function(){ 211 | $http.get('f_minerHardCtl.php?command='+(command)).success(function(d){ 212 | if(d.info){ 213 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 214 | } 215 | $scope.tick(); 216 | }); 217 | } 218 | $timeout(execute, 1000); 219 | }; 220 | 221 | $scope.hostHardCtl = function(command) { 222 | $scope.tick(); 223 | var execute = function(){ 224 | $http.get('f_hostHardCtl.php?command='+(command)+'&pass=p0c4t0p4').success(function(d){ 225 | if(d.info){ 226 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 227 | } 228 | $scope.tick(); 229 | }); 230 | } 231 | $timeout(execute, 1000); 232 | }; 233 | 234 | $scope.poolAdd = function(a) { 235 | a = a || {}; 236 | $scope.pools.push(a); 237 | $scope.poolForm.$setDirty() 238 | }; 239 | $scope.poolRemove = function(index) { 240 | $scope.pools.splice(index,1); 241 | $scope.poolForm.$setDirty() 242 | }; 243 | $scope.poolSave = function() { 244 | $scope.sync('pools',$scope.pools,1); 245 | $scope.poolForm.$setPristine(); 246 | }; 247 | $scope.poolBack = function() { 248 | $scope.sync('pools',0,1); 249 | $scope.poolForm.$setPristine(); 250 | }; 251 | 252 | $scope.optionAdd = function(a) { 253 | a = a || {}; 254 | $scope.options.push(a); 255 | $scope.optionForm.$setDirty() 256 | }; 257 | $scope.optionRemove = function(index) { 258 | $scope.options.splice(index,1); 259 | $scope.optionForm.$setDirty() 260 | }; 261 | $scope.optionSave = function() { 262 | $scope.sync('options',$scope.options,1); 263 | $scope.optionForm.$setPristine(); 264 | }; 265 | $scope.optionBack = function() { 266 | $scope.sync('options',0,1); 267 | $scope.optionForm.$setPristine(); 268 | }; 269 | }) 270 | 271 | 272 | .controller('CtrlSettings', function($scope) { 273 | $scope.status.extra=true; 274 | }) 275 | 276 | 277 | .controller('CtrlBackup', function($scope,$http,$timeout) { 278 | $scope.thisFolder = '/opt/scripta/'; 279 | $scope.backupFolder = '/opt/scripta/backup/'; 280 | $scope.backupName = GetDateTime(); 281 | $scope.backups = []; 282 | $scope.restoring = 0; 283 | $scope.items = [ 284 | {selected:true,name:'etc/scripta.conf'}, 285 | {selected:true,name:'etc/miner.pools.json'}, 286 | {selected:true,name:'etc/miner.options.json'} 287 | ]; 288 | 289 | $scope.addItem = function() { 290 | $scope.items.push({selected:true,name:$scope.newItem}); 291 | $scope.newItem = ''; 292 | }; 293 | $scope.selItem = function() { 294 | var count = 0; 295 | angular.forEach($scope.items, function(item) { 296 | count += item.selected ? 1 : 0; 297 | }); 298 | return count; 299 | }; 300 | 301 | 302 | $scope.backupLocal = function() { 303 | var promise = $http.get('f_backup.php?name='+$scope.backupName+'&backup='+angular.toJson($scope.items)).success(function(d){ 304 | if(d.info){ 305 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 306 | } 307 | angular.forEach(d.data, function(v,k) { 308 | if(v.success){ 309 | $scope.items[k].bak=true; 310 | $scope.items[k].selected=false; 311 | } 312 | else{ 313 | $scope.items[k].fail=true; 314 | } 315 | });// Add to existing 316 | $scope.reload(); 317 | }); 318 | return promise; 319 | }; 320 | 321 | $scope.backupExport = function() { 322 | $scope.backupLocal().then(function(){ 323 | $scope.exportZip($scope.backupName); 324 | }); 325 | }; 326 | 327 | $scope.exportZip = function(name) { 328 | name=name||$scope.backups[$scope.restoring].dir; 329 | window.location.href='f_backup.php?export='+name; 330 | }; 331 | 332 | $scope.choose = function(i) { 333 | $scope.restoring=i; 334 | }; 335 | 336 | $scope.restore = function() { 337 | $http.get('f_backup.php?restore='+$scope.backups[$scope.restoring].dir).success(function(d){ 338 | if(d.info){ 339 | angular.forEach(d.info, function(v,k) {Alertify.log.create(v.type, v.text);}); 340 | } 341 | $scope.syncDelay(300,'settings'); 342 | $scope.syncDelay(600,'pools'); 343 | $scope.syncDelay(900,'options'); 344 | }); 345 | }; 346 | 347 | $scope.reload = function(wait) { 348 | wait=wait||0; 349 | var syncNow = function(){ 350 | $http.get('f_backup.php').success(function(d){ 351 | if(d.data){ 352 | $scope.backups=d.data; 353 | } 354 | }); 355 | } 356 | //return 357 | $timeout(syncNow, wait); 358 | }; 359 | $scope.reload(); 360 | }); 361 | 362 | 363 | function GetDateTime() { 364 | var now = new Date(); 365 | return [[now.getFullYear(),AddZero(now.getMonth() + 1),AddZero(now.getDate())].join(''), [AddZero(now.getHours()), AddZero(now.getMinutes())].join('')].join('-'); 366 | } 367 | 368 | function AddZero(num) { 369 | return (num >= 0 && num < 10) ? '0' + num : num + ''; 370 | } 371 | -------------------------------------------------------------------------------- /var/www/ng/directives.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Directives */ 4 | angular.module('Scripta.directives', []) 5 | 6 | // Sets background color by interpolating between green and red. 7 | // Thinking about oth interpolation functions or maybe more colors 8 | .directive('statusItem', function() { 9 | return function(scope, element, attrs) { 10 | var i=attrs.statusItem; 11 | var g=attrs.good; // Threshold good: green 12 | var b=attrs.bad; // Threshold bad: red 13 | 14 | function update(){ 15 | var x=2*(i-g)/(b-g); 16 | x= x<0 ?0:x; 17 | x= x>2 ?2:x; 18 | element.css('background',(b==g)?'#666':'rgb('+Math.round(Math.min(x, 1)*(217-92)+92)+','+Math.round((2 - Math.max(x, 1)) * (184-83)+83)+',85)'); 19 | element.css('color','#fff'); 20 | } 21 | 22 | scope.$watch(attrs.good, function(v) {g=v;update();}); 23 | scope.$watch(attrs.bad, function(v) {b=v;update();}); 24 | scope.$watch(attrs.statusItem, function(v) {i=v;update();}); 25 | } 26 | }) 27 | // Toggles .active based on $location.path() 28 | .directive('menuActive', function($rootScope,$location) { 29 | return function(scope, element, attrs) { 30 | $rootScope.$on('$routeChangeStart', function (event, next, current) { 31 | (element.children()[0].hash === '#'+$location.path()) ? element.addClass('active') : element.removeClass('active'); 32 | }); 33 | } 34 | }) 35 | 36 | .directive('graphLive', function () { 37 | return { 38 | restrict: 'C', 39 | scope: { 40 | live: '=' 41 | }, 42 | controller: function ($scope, $element, $attrs) { 43 | }, 44 | link: function (scope, element, attrs) { 45 | var chart = new Highcharts.Chart({ 46 | chart: { 47 | renderTo: attrs.id, 48 | type: 'areaspline', 49 | spacingLeft: 0, 50 | spacingRight: 0 51 | }, 52 | colors: ['rgb(0,0,0)'], 53 | legend: {enabled: false}, 54 | subtitle: {text: ''}, 55 | title: { 56 | text: 'Hashrate', 57 | align: 'center', 58 | verticalAlign: 'bottom', 59 | }, 60 | xAxis: { 61 | type: 'datetime', 62 | minPadding: 0, 63 | maxPadding: 0, 64 | tickPixelInterval: 120 65 | }, 66 | yAxis: { 67 | tickPixelInterval: 30, 68 | title: { 69 | text: '' 70 | }, 71 | opposite: true 72 | }, 73 | tooltip: { 74 | formatter: function() { 75 | var hs=this.y/1000,h=this.y+' '; 76 | if(hs > 10){h=hs.toPrecision(4)+' k';}hs/=1000; 77 | if(hs > 10){h=hs.toPrecision(4)+' M';}hs/=1000; 78 | if(hs > 10){h=hs.toPrecision(4)+' G';}hs/=1000; 79 | if(hs > 10){h=hs.toPrecision(4)+' T';} 80 | return Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'
'+ h +'h/s'; 81 | } 82 | }, 83 | plotOptions: { 84 | areaspline: { 85 | fillOpacity: 0.1, 86 | marker: { 87 | enabled: false, 88 | states: { 89 | hover: { 90 | enabled: true 91 | } 92 | } 93 | } 94 | } 95 | }, 96 | series: [{ 97 | name: 'hashrate', 98 | data: [[Date.now(),0]] 99 | }] 100 | }); 101 | 102 | var liveTrack=0; 103 | scope.$watch('live', function (newlist) { 104 | var n=angular.copy(newlist); 105 | if(!n || !n.length)return; 106 | if(liveTrack<2){ 107 | chart.series[0].setData(n); 108 | } 109 | else{ 110 | chart.series[0].addPoint(n[n.length-1],true,n.lengthBackup settings 2 | 3 |
4 |
5 |
6 | 7 |
8 |
9 | {{backupFolder}} 10 | 11 |
12 |
13 |
14 |
15 | 19 |
20 |
21 | 27 |
28 |
29 |
30 |
31 |
32 |
33 | {{thisFolder}} 34 | 35 |
36 | 37 |
38 |
39 |
40 |
41 |
42 |
43 |

44 | Add Item allows you to include more files and/or folders into a backup.
45 | Backup to device will copy the selected items to the specified folder in the backup folder.
46 | Export will make a backup on device and then serve it as a download. 47 |

48 |

49 | Backed up items will be confirmed by a green label. Problematic items get a red label.
50 | Click backup again and MinePeon will attempt to backup the not yet backed up items again. 51 |

52 | 53 | 54 |
55 |
56 |
57 |
58 | 59 |

Restore settings from backup

60 |
61 |
62 |
63 | {{b.dir}} 64 |
65 |
66 |
67 |
68 | There seems to be no files in this backup, this can happen if permission was denied. 69 |
70 |
71 |
72 | {{i}} 73 |
74 |
75 |

76 | Reload list will scan the backup folder for saved backups.
77 | Restore will copy the items in the currently selected backup to the active MinePeon folder. Restart the miner to let it use the restored settings.
78 | Export ... will make a zipfile of the items in the currently selected backup and serve it as a download.
79 | Import file... lets you upload a zip file and will add it to the list of backups. If it does not show up, try to reload the list. 80 |

81 | 82 | 83 | 84 | 85 |
86 |
87 | 88 |
89 |
90 | 91 | 92 |
93 | 94 |
-------------------------------------------------------------------------------- /var/www/partials/miner.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 | 7 | 8 | 9 | 10 |

Available pools

11 |

12 | Click to add pool to pool's list 13 |

14 | 27 |
28 |
29 |
30 |
31 |
32 |

33 | 34 |

35 |

36 | Ordered from gentle to rough. 37 |

38 |
39 | Reset 40 | Start 41 | Stop 42 | Shutdown 43 | Reboot 44 |
45 |
46 |
47 | 48 |

Pools

49 |

50 | The settings below serve as direct input to the miner. One little error can and will let the miner crash. 51 |

52 |
53 |
54 | 55 | 56 | 57 | 58 |
59 |
60 |
61 | 62 |
63 |
64 | 65 |
66 |
67 | 68 |
69 |
70 |
71 | 72 |
73 | 74 |
75 |
76 |
77 |
78 | 79 | 80 | 81 |
82 | 83 |

Options more info on GitHub (gc3355)

84 | 85 |
86 |
87 | 88 | 89 |
90 |
91 |
92 | 93 |
94 |
95 |
96 | 97 |
98 | 99 |
100 |
101 |
102 |
103 | 104 | 105 | 106 |
107 |
108 | 109 | Reload settings 2 |

Scr|pta

3 |
4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 | 27 |
28 | 29 |
30 |
31 |

32 | Automatic will refresh quickly on page load or if the miner was down recently. The refresh interval will slowly rise.
33 | Graph points is the amount of data points shown on the live graph. 50 is good. 34 |

35 |
36 |
37 |
38 | 39 |
40 |
x
41 |
42 | 43 |
44 | 45 |

{{settings.date}}

46 |
47 |
48 |
49 |
50 | 51 |
52 |
53 |
54 | 55 |
56 | 57 |
58 | 59 |
60 | 61 |
62 |
63 |

64 | Web password is needed to access this interface. Default password is p. It cannot be empty. Changing it will log you out. 65 |

66 |
67 |
68 |
69 |

70 | 71 | 72 |

73 |
74 | 75 | 76 |
77 |

Mining

78 |
79 |
80 | 81 |
82 | 83 | 84 | 85 | 88 | 91 | 92 | 95 | 96 |

97 | Remote control shares stats with a remote server. Scripta will accept commands from the server.
98 | Automatic recovery responds to alert events by restarting the miner. First gently, then rough.
99 | E-mail alerts send an e-mail when alerts events are fired.
100 | Donation donates a couple of mining minutes to the Scripta project. 101 |

102 |
103 |
104 |
105 | 106 |
107 |
108 | 109 | MH/s 110 |
111 |
112 | 113 |
114 | 115 |
116 |
117 |

118 | When Expected hashrate is higher than the hashrate reported by cgminer an alert event will be fired.
119 | When Expected devices is higher than the device count reported by cgminer an alert event will be fired. 120 |

121 |
122 |
123 |
124 |

125 | 126 |

127 |
128 | 129 | 130 |
131 |
132 |

Remote control

133 |
134 | 135 |
136 | 137 |

138 | Use this key to let a Remote Control server authenticate to your Scripta. 139 |

140 |
141 |
142 |
143 | 167 |
168 |

E-mail alerts

169 |
170 | 171 |
172 | 173 |
174 |
175 |
176 | 177 |
178 | 179 |
180 |
181 |
182 | 183 |
184 | 185 |

Please choose your own SMTP server ip address.

186 |
187 |
188 |
189 | 190 |
191 | 192 |

Please choose your own SMTP server port.

193 |
194 |
195 | 196 |
197 | 198 |
199 | 200 |

Please choose your own user name for SMTP server.

201 |
202 |
203 |
204 | 205 |
206 | 207 |

Please choose your own password for SMTP server.

208 |
209 |
210 |
211 | 212 |

213 | 214 |

215 |
216 | -------------------------------------------------------------------------------- /var/www/partials/status.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Graphs 4 | 5 | Static - 6 | Live - 7 | Refresh - 8 | More 9 | 10 |

11 | 12 |

13 | No image 14 | No image 15 |

16 |

17 | No image 18 | No image 19 |

20 |

21 | No image 22 |

23 |
24 | 25 |
26 |

27 | Graphs 28 | 29 | Static - 30 | Live - 31 | Refresh - 32 | Auto-refresh in {{counter}}s 33 | 34 |

35 | 36 |
37 |
38 | 39 |
40 |
No devices running
41 |

Devices

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 |
DeviceIDTempHashrate 5sHashrate avAcceptedRejectedHW ErrorsUtilityLast Share Time
{{d.Temperature}} °C{{(d.MHS5s*1024)}} Kh/s{{(d.MHSav*1024)}} Kh/s
{{status.dtot.devices}} devsTotals{{status.dtot.MHS5s|mhs}}h/s{{status.dtot.MHSav|mhs}}h/s" . $ . "
84 | 85 |
No pools loaded
86 |

Pools

87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |
URLUserStatus
Pr
GW
Acc
Rej
Disc
Last
Diff1
DAcc
DRej
DLast
Best
127 | -------------------------------------------------------------------------------- /var/www/rrd: -------------------------------------------------------------------------------- 1 | /opt/scripta/http/rrd/ -------------------------------------------------------------------------------- /var/www/test.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /var/www/update/ctrl.php: -------------------------------------------------------------------------------- 1 | currentVersionName = CURRENT_VERSION_NAME; 7 | $update->currentVersion = CURRENT_VERSION; 8 | $update->updateUrl = REPOSITORY_URL; 9 | 10 | //Check for a new update 11 | $latest = $update->checkUpdate(); 12 | 13 | if ($latest !== false) { 14 | if ($latest > $update->currentVersion) { 15 | //Install new update 16 | echo "An update is available.\nDo you want to download and install it now?\nMining activities will not be affected.\nCurrent Version: ".$update->currentVersionName."\nNew version: ".$update->latestVersionName; 17 | } 18 | else { 19 | //echo "Current Version is up to date"; 20 | echo ''; 21 | } 22 | } 23 | else { 24 | echo $update->getLastError(); 25 | } 26 | 27 | ?> -------------------------------------------------------------------------------- /var/www/update/start.php: -------------------------------------------------------------------------------- 1 | currentVersionName = CURRENT_VERSION_NAME; 7 | $update->currentVersion = CURRENT_VERSION; 8 | $update->updateUrl = REPOSITORY_URL; 9 | 10 | //Check for a new update 11 | echo "Download file...\n"; 12 | $latest = $update->checkUpdate(); 13 | if ($latest !== false) { 14 | if ($latest > $update->currentVersion) { 15 | //Install new update 16 | echo "Installing Update...\n"; 17 | if ($update->update()) { 18 | echo "Update successful!"; 19 | } 20 | else { 21 | echo "Update failed!"; 22 | } 23 | 24 | } 25 | else { 26 | echo "Current Version is up to date"; 27 | } 28 | } 29 | else { 30 | echo $update->getLastError(); 31 | } 32 | 33 | ?> 34 | -------------------------------------------------------------------------------- /var/www/update/update.php: -------------------------------------------------------------------------------- 1 | _log = $log; 89 | } 90 | 91 | /* 92 | * Log a message if logging is enabled 93 | * 94 | * @param string $message The message 95 | * 96 | * @return void 97 | */ 98 | public function log($message) { 99 | if ($this->_log) { 100 | $this->_lastError = $message; 101 | 102 | $log = fopen($this->logFile, 'a'); 103 | 104 | if ($log) { 105 | $message = date('').$message."\n"; 106 | fputs($log, $message); 107 | fclose($log); 108 | } 109 | else { 110 | die('Could not write log file!'); 111 | } 112 | } 113 | } 114 | 115 | /* 116 | * Get the latest error 117 | * 118 | * @return string Last error 119 | */ 120 | public function getLastError() { 121 | if (!is_null($this->_lastError)) 122 | return $this->_lastError; 123 | else 124 | return false; 125 | } 126 | 127 | private function _removeDir($dir) { 128 | if (is_dir($dir)) { 129 | $objects = scandir($dir); 130 | foreach ($objects as $object) { 131 | if ($object != "." && $object != "..") { 132 | if (filetype($dir."/".$object) == "dir") 133 | $this->_removeDir($dir."/".$object); 134 | else 135 | unlink($dir."/".$object); 136 | } 137 | } 138 | reset($objects); 139 | rmdir($dir); 140 | } 141 | } 142 | 143 | /* 144 | * Check for a new version 145 | * 146 | * @return string The latest version 147 | */ 148 | public function checkUpdate() { 149 | $this->log('Checking for a new update. . .'); 150 | 151 | $updateFile = $this->updateUrl.'/update.ini'; 152 | 153 | $update = @file_get_contents($updateFile); 154 | if ($update === false) { 155 | $this->log('Could not retrieve update file `'.$updateFile.'`!'); 156 | return false; 157 | } 158 | else { 159 | $versions = parse_ini_string($update, true); 160 | if (is_array($versions)) { 161 | $keyOld = 0; 162 | $latest = 0; 163 | $update = ''; 164 | 165 | foreach ($versions as $key => $version) { 166 | 167 | if ($key > $keyOld) { 168 | $keyOld = $key; 169 | $latest = $version['version']; 170 | $update = $version['url']; 171 | } 172 | } 173 | 174 | $this->log('New version found `'.$latest.'`.'); 175 | $this->latestVersion = $keyOld; 176 | $this->latestVersionName = $latest; 177 | $this->latestUpdate = $update; 178 | 179 | return $keyOld; 180 | } 181 | else { 182 | $this->log('Unable to parse update file!'); 183 | return false; 184 | } 185 | } 186 | } 187 | 188 | /* 189 | * Download the update 190 | * 191 | * @param string $updateUrl Url where to download from 192 | * @param string $updateFile Path where to save the download 193 | */ 194 | public function downloadUpdate($updateUrl, $updateFile) { 195 | $this->log('Downloading update...'); 196 | $update = @file_get_contents($updateUrl); 197 | 198 | if ($update === false) { 199 | $this->log('Could not download update `'.$updateUrl.'`!'); 200 | return false; 201 | } 202 | 203 | $handle = fopen($updateFile, 'w'); 204 | 205 | if (!$handle) { 206 | $this->log('Could not save update file `'.$updateFile.'`!'); 207 | return false; 208 | } 209 | 210 | if (!fwrite($handle, $update)) { 211 | $this->log('Could not write to update file `'.$updateFile.'`!'); 212 | return false; 213 | } 214 | 215 | fclose($handle); 216 | 217 | return true; 218 | } 219 | 220 | /* 221 | * Install update 222 | * 223 | * @param string $updateFile Path to the update file 224 | */ 225 | public function install($updateFile) { 226 | $zip = zip_open($updateFile); 227 | 228 | while ($file = zip_read($zip)) { 229 | $filename = zip_entry_name($file); 230 | $foldername = $this->installDir.dirname($filename); 231 | 232 | $this->log('Updating `'.$filename.'`!'); 233 | 234 | if (!is_dir($foldername)) { 235 | if (!mkdir($foldername, $this->dirPermissions, true)) { 236 | $this->log('Could not create folder `'.$foldername.'`!'); 237 | } 238 | } 239 | 240 | $contents = zip_entry_read($file, zip_entry_filesize($file)); 241 | 242 | //Skip if entry is a directory 243 | if (substr($filename, -1, 1) == '/') 244 | continue; 245 | 246 | //Write to file 247 | if (!is_writable($this->installDir.$filename)) { 248 | $this->log('Could not update `'.$this->installDir.$filename.'`, not writeable!'); 249 | return false; 250 | } 251 | 252 | $updateHandle = @fopen($this->installDir.$filename, 'w'); 253 | 254 | if (!$updateHandle) { 255 | $this->log('Could not update file `'.$this->installDir.$filename.'`!'); 256 | return false; 257 | } 258 | 259 | if (!fwrite($updateHandle, $contents)) { 260 | $this->log('Could not write to file `'.$this->installDir.$filename.'`!'); 261 | return false; 262 | } 263 | 264 | fclose($updateHandle); 265 | 266 | //If file is a update script, include 267 | if ($filename == $this->updateScriptName) { 268 | $this->log('Try to include update script `'.$this->installDir.$filename.'`.'); 269 | require($this->installDir.$filename); 270 | $this->log('Update script `'.$this->installDir.$filename.'` included!'); 271 | unlink($this->installDir.$filename); 272 | } 273 | } 274 | 275 | zip_close($zip); 276 | 277 | if ($this->removeTempDir) { 278 | $this->log('Temporary directory `'.$this->tempDir.'` deleted.'); 279 | $this->_removeDir($this->tempDir); 280 | } 281 | 282 | $this->log('Update `'.$this->latestVersion.'` installed.'); 283 | 284 | return true; 285 | } 286 | 287 | 288 | /* 289 | * Update to the latest version 290 | */ 291 | public function update() { 292 | //Check for latest version 293 | if ((is_null($this->latestVersion)) or (is_null($this->latestUpdate))) { 294 | $this->checkUpdate(); 295 | } 296 | 297 | if ((is_null($this->latestVersion)) or (is_null($this->latestUpdate))) { 298 | return false; 299 | } 300 | 301 | //Update 302 | if ($this->latestVersion > $this->currentVersion) { 303 | $this->log('Updating...'); 304 | 305 | //Add slash at the end of the path 306 | if ($this->tempDir[strlen($this->tempDir)-1] != '/'); 307 | $this->tempDir = $this->tempDir.'/'; 308 | 309 | if ((!is_dir($this->tempDir)) and (!mkdir($this->tempDir, 0777, true))) { 310 | $this->log('Temporary directory `'.$this->tempDir.'` does not exist and could not be created!'); 311 | return false; 312 | } 313 | 314 | if (!is_writable($this->tempDir)) { 315 | $this->log('Temporary directory `'.$this->tempDir.'` is not writeable!'); 316 | return false; 317 | } 318 | 319 | $updateFile = $this->tempDir.'/'.$this->latestVersion.'.zip'; 320 | $updateUrl = $this->updateUrl.'/'.$this->latestVersion.'.zip'; 321 | 322 | //Download update 323 | if (!is_file($updateFile)) { 324 | if (!$this->downloadUpdate($updateUrl, $updateFile)) { 325 | $this->log('Failed to download update!'); 326 | return false; 327 | } 328 | 329 | $this->log('Latest update downloaded to `'.$updateFile.'`.'); 330 | } 331 | else { 332 | $this->log('Latest update already downloaded to `'.$updateFile.'`.'); 333 | } 334 | 335 | //Unzip 336 | return $this->install($updateFile); 337 | } 338 | else { 339 | $this->log('No update available!'); 340 | return false; 341 | } 342 | } 343 | } -------------------------------------------------------------------------------- /var/www/update/version.php: -------------------------------------------------------------------------------- 1 | 6 | --------------------------------------------------------------------------------