266 lines
9.9 KiB
Python
266 lines
9.9 KiB
Python
import asyncio
|
|
import ipaddress
|
|
import os
|
|
import re
|
|
import sys
|
|
import time
|
|
from operator import itemgetter
|
|
|
|
import PySimpleGUI as sg
|
|
import aiofiles
|
|
import toml
|
|
|
|
from miners.miner_factory import MinerFactory
|
|
from network import MinerNetwork
|
|
|
|
layout = [
|
|
[sg.Text('Network IP: '), sg.InputText(key='miner_network', do_not_clear=True, size=(90, 1)),
|
|
sg.Button('Scan', key='scan'),
|
|
sg.Text("", key="status")],
|
|
[sg.Text('IP List File: '), sg.Input(key="file_iplist", do_not_clear=True, size=(90, 1)), sg.FileBrowse(),
|
|
sg.Button('Import', key="import_iplist")],
|
|
[sg.Text('Config File: '), sg.Input(key="file_config", do_not_clear=True, size=(90, 1)), sg.FileBrowse(),
|
|
sg.Button('Import', key="import_file_config"), sg.Button('Export', key="export_file_config")],
|
|
[
|
|
sg.Column([
|
|
[sg.Text("IP List:", pad=(0, 0)), sg.Text("", key="ip_count", pad=(1, 0), size=(3, 1)),
|
|
sg.Button('ALL', key="select_all_ips")],
|
|
[sg.Listbox([], size=(20, 32), key="ip_list", select_mode='extended')]
|
|
]),
|
|
sg.Column([
|
|
[sg.Text("Data: ", pad=(0, 0)), sg.Button('GET', key="get_data"), sg.Button('SORT IP', key="sort_data_ip"), sg.Button('SORT HR', key="sort_data_hr"), sg.Button('SORT USER', key="sort_data_user")],
|
|
[sg.Listbox([], size=(50, 32), key="hr_list")]
|
|
]),
|
|
sg.Column([
|
|
[sg.Text("Config"), sg.Button("IMPORT", key="import_config"), sg.Button("CONFIG", key="send_config"),
|
|
sg.Button("LIGHT", key="light"), sg.Button("GENERATE", key="generate_config")],
|
|
[sg.Multiline(size=(50, 34), key="config", do_not_clear=True)],
|
|
])
|
|
],
|
|
]
|
|
|
|
window = sg.Window('Upstream Config Util', layout)
|
|
miner_factory = MinerFactory()
|
|
|
|
|
|
async def update_ui_with_data(key, data, append=False):
|
|
if append:
|
|
data = window[key].get_text() + data
|
|
window[key].update(data)
|
|
|
|
|
|
async def scan_network(network):
|
|
global window
|
|
await update_ui_with_data("status", "Scanning")
|
|
miners = await network.scan_network_for_miners()
|
|
window["ip_list"].update([str(miner.ip) for miner in miners])
|
|
await update_ui_with_data("ip_count", str(len(miners)))
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def miner_light(ips: list):
|
|
await asyncio.gather(flip_light(ip) for ip in ips)
|
|
|
|
|
|
async def flip_light(ip):
|
|
listbox = window['ip_list'].Widget
|
|
miner = await miner_factory.get_miner(ip)
|
|
if ip in window["ip_list"].Values:
|
|
index = window["ip_list"].Values.index(ip)
|
|
if listbox.itemcget(index, "background") == 'red':
|
|
listbox.itemconfigure(index, bg='#f0f3f7', fg='#000000')
|
|
await miner.fault_light_off()
|
|
else:
|
|
listbox.itemconfigure(index, bg='red', fg='white')
|
|
await miner.fault_light_on()
|
|
|
|
|
|
async def import_config(ip):
|
|
await update_ui_with_data("status", "Importing")
|
|
miner = await miner_factory.get_miner(ipaddress.ip_address(*ip))
|
|
await miner.get_config()
|
|
config = miner.config
|
|
await update_ui_with_data("config", toml.dumps(config))
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def import_iplist(file_location):
|
|
await update_ui_with_data("status", "Importing")
|
|
if not os.path.exists(file_location):
|
|
return
|
|
else:
|
|
ip_list = []
|
|
async with aiofiles.open(file_location, mode='r') as file:
|
|
async for line in file:
|
|
ips = [x.group() for x in re.finditer(
|
|
"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)", line)]
|
|
for ip in ips:
|
|
if ip not in ip_list:
|
|
ip_list.append(ipaddress.ip_address(ip))
|
|
ip_list.sort()
|
|
window["ip_list"].update([str(ip) for ip in ip_list])
|
|
await update_ui_with_data("ip_count", str(len(ip_list)))
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def send_config(ips: list, config):
|
|
await update_ui_with_data("status", "Configuring")
|
|
config['format']['generator'] = 'upstream_config_util'
|
|
config['format']['timestamp'] = int(time.time())
|
|
tasks = []
|
|
for ip in ips:
|
|
tasks.append(miner_factory.get_miner(ip))
|
|
miners = await asyncio.gather(*tasks)
|
|
tasks = []
|
|
for miner in miners:
|
|
tasks.append(miner.send_config(config))
|
|
await asyncio.gather(*tasks)
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def import_config_file(file_location):
|
|
await update_ui_with_data("status", "Importing")
|
|
if not os.path.exists(file_location):
|
|
return
|
|
else:
|
|
async with aiofiles.open(file_location, mode='r') as file:
|
|
config = await file.read()
|
|
await update_ui_with_data("config", str(config))
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def export_config_file(file_location, config):
|
|
await update_ui_with_data("status", "Exporting")
|
|
config = toml.loads(config)
|
|
config['format']['generator'] = 'upstream_config_util'
|
|
config['format']['timestamp'] = int(time.time())
|
|
config = toml.dumps(config)
|
|
async with aiofiles.open(file_location, mode='w+') as file:
|
|
await file.write(config)
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def get_data(ip_list: list):
|
|
await update_ui_with_data("status", "Getting Data")
|
|
ips = [ipaddress.ip_address(ip) for ip in ip_list]
|
|
ips.sort()
|
|
data = await asyncio.gather(*[get_formatted_data(miner) for miner in ips])
|
|
window["hr_list"].update(disabled=False)
|
|
window["hr_list"].update([item['IP'] + " | " + str(item['TH/s']) + " TH/s | " + item['user'] for item in data])
|
|
window["hr_list"].update(disabled=True)
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def get_formatted_data(ip: ipaddress.ip_address):
|
|
miner = await miner_factory.get_miner(ip)
|
|
data = await miner.api.multicommand("summary", "pools")
|
|
mh5s = round(data['summary'][0]['SUMMARY'][0]['MHS 5s'] / 1000000, 2)
|
|
user = data['pools'][0]['POOLS'][0]['User']
|
|
return {'TH/s': mh5s, 'IP': str(miner.ip), 'user': user}
|
|
|
|
|
|
async def generate_config():
|
|
config = {'group': [{
|
|
'name': 'group',
|
|
'quota': 1,
|
|
'pool': [{
|
|
'url': 'stratum2+tcp://us-east.stratum.slushpool.com/u95GEReVMjK6k5YqiSFNqqTnKU4ypU2Wm8awa6tmbmDmk1bWt',
|
|
'user': 'UpstreamDataInc.test',
|
|
'password': '123'
|
|
}, {
|
|
'url': 'stratum2+tcp://stratum.slushpool.com/u95GEReVMjK6k5YqiSFNqqTnKU4ypU2Wm8awa6tmbmDmk1bWt',
|
|
'user': 'UpstreamDataInc.test',
|
|
'password': '123'
|
|
}, {
|
|
'url': 'stratum+tcp://stratum.slushpool.com:3333',
|
|
'user': 'UpstreamDataInc.test',
|
|
'password': '123'
|
|
}]
|
|
}],
|
|
'format': {
|
|
'version': '1.2+',
|
|
'model': 'Antminer S9',
|
|
'generator': 'upstream_config_util',
|
|
'timestamp': int(time.time())
|
|
},
|
|
'temp_control': {
|
|
'target_temp': 80.0,
|
|
'hot_temp': 90.0,
|
|
'dangerous_temp': 120.0
|
|
},
|
|
'autotuning': {
|
|
'enabled': True,
|
|
'psu_power_limit': 900
|
|
}
|
|
}
|
|
window['config'].update(toml.dumps(config))
|
|
|
|
async def sort_data(index: int):
|
|
await update_ui_with_data("status", "Sorting Data")
|
|
data_list = window['hr_list'].Values
|
|
new_list = []
|
|
for item in data_list:
|
|
item_data = [part.strip() for part in item.split("|")]
|
|
item_data[1] = item_data[1].replace(" TH/s", "")
|
|
item_data[0] = ipaddress.ip_address(item_data[0])
|
|
new_list.append(item_data)
|
|
if index == 1:
|
|
new_data_list = sorted(new_list, key=lambda x: float(x[index]))
|
|
else:
|
|
new_data_list = sorted(new_list, key=itemgetter(index))
|
|
new_data_list = [str(item[0]) + " | " + item[1] + " TH/s | " + item[2] for item in new_data_list]
|
|
window["hr_list"].update(disabled=False)
|
|
window["hr_list"].update(new_data_list)
|
|
window["hr_list"].update(disabled=True)
|
|
await update_ui_with_data("status", "")
|
|
|
|
|
|
async def ui():
|
|
while True:
|
|
event, value = window.read(timeout=10)
|
|
if event in (None, 'Close'):
|
|
sys.exit()
|
|
if event == 'scan':
|
|
if len(value['miner_network'].split("/")) > 1:
|
|
network = value['miner_network'].split("/")
|
|
miner_network = MinerNetwork(ip_addr=network[0], mask=network[1])
|
|
else:
|
|
miner_network = MinerNetwork(value['miner_network'])
|
|
asyncio.create_task(scan_network(miner_network))
|
|
if event == 'select_all_ips':
|
|
if value['ip_list'] == window['ip_list'].Values:
|
|
window['ip_list'].set_value([])
|
|
else:
|
|
window['ip_list'].set_value(window['ip_list'].Values)
|
|
if event == 'import_config':
|
|
if 2 > len(value['ip_list']) > 0:
|
|
asyncio.create_task(import_config(value['ip_list']))
|
|
if event == 'light':
|
|
asyncio.create_task(miner_light(value['ip_list']))
|
|
if event == "import_iplist":
|
|
asyncio.create_task(import_iplist(value["file_iplist"]))
|
|
if event == "send_config":
|
|
asyncio.create_task(send_config(value['ip_list'], toml.loads(value['config'])))
|
|
if event == "import_file_config":
|
|
asyncio.create_task(import_config_file(value['file_config']))
|
|
if event == "export_file_config":
|
|
asyncio.create_task(export_config_file(value['file_config'], value["config"]))
|
|
if event == "get_data":
|
|
asyncio.create_task(get_data(value['ip_list']))
|
|
if event == "generate_config":
|
|
asyncio.create_task(generate_config())
|
|
if event == "sort_data_ip":
|
|
asyncio.create_task(sort_data(0))
|
|
if event == "sort_data_hr":
|
|
asyncio.create_task(sort_data(1))
|
|
if event == "sort_data_user":
|
|
print()
|
|
asyncio.create_task(sort_data(2))
|
|
if event == "__TIMEOUT__":
|
|
await asyncio.sleep(0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
loop = asyncio.new_event_loop()
|
|
loop.run_until_complete(ui())
|