Compare commits
28 Commits
v0.8.2
...
v0.8.4-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5261b00aad | ||
|
|
f18d37a19e | ||
|
|
7c3af3da41 | ||
|
|
8948af55f2 | ||
|
|
dd8fe41ad1 | ||
|
|
198eedcd43 | ||
|
|
f7309decdb | ||
|
|
078579d8e1 | ||
|
|
39eeb13409 | ||
|
|
dfccd67ccb | ||
|
|
10949225c0 | ||
|
|
3a60a3584a | ||
|
|
480aab550c | ||
|
|
fa83e61249 | ||
|
|
2f3411e12d | ||
|
|
3e7311687e | ||
|
|
bc2d549ce5 | ||
|
|
3d31d89c9e | ||
|
|
15fc27e6fa | ||
|
|
943ebc77a1 | ||
|
|
733437ef03 | ||
|
|
b444245e98 | ||
|
|
481d31a0f1 | ||
|
|
264db3bdd6 | ||
|
|
d292b9c195 | ||
|
|
dce25a679f | ||
|
|
c903631742 | ||
|
|
e70bfdc886 |
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
venv/
|
||||||
|
build/
|
||||||
|
__pycache__/
|
||||||
|
pyvenv.cfg
|
||||||
|
.env/
|
||||||
|
bin/
|
||||||
|
lib/
|
||||||
@@ -171,7 +171,10 @@ If you are sure you want to use this command please use API.send_command("{item}
|
|||||||
return False, data["Msg"]
|
return False, data["Msg"]
|
||||||
else:
|
else:
|
||||||
# make sure the command succeeded
|
# make sure the command succeeded
|
||||||
if data["STATUS"][0]["STATUS"] not in ("S", "I"):
|
if type(data["STATUS"]) == str:
|
||||||
|
if data["STATUS"] in ["RESTART"]:
|
||||||
|
return True, None
|
||||||
|
elif data["STATUS"][0]["STATUS"] not in ("S", "I"):
|
||||||
# this is an error
|
# this is an error
|
||||||
if data["STATUS"][0]["STATUS"] not in ("S", "I"):
|
if data["STATUS"][0]["STATUS"] not in ("S", "I"):
|
||||||
return False, data["STATUS"][0]["Msg"]
|
return False, data["STATUS"][0]["Msg"]
|
||||||
@@ -197,8 +200,12 @@ If you are sure you want to use this command please use API.send_command("{item}
|
|||||||
str_data = str_data.replace("}{", "},{")
|
str_data = str_data.replace("}{", "},{")
|
||||||
# fix an error with a bmminer return having a specific comma that breaks json.loads()
|
# fix an error with a bmminer return having a specific comma that breaks json.loads()
|
||||||
str_data = str_data.replace("[,{", "[{")
|
str_data = str_data.replace("[,{", "[{")
|
||||||
# fix an error with a btminer return having a specific comma that breaks json.loads()
|
# fix an error with Avalonminers returning inf and nan
|
||||||
str_data = str_data.replace("inf", "0")
|
str_data = str_data.replace("inf", "0")
|
||||||
|
str_data = str_data.replace("nan", "0")
|
||||||
|
# fix whatever this garbage from avalonminers is `,"id":1}`
|
||||||
|
if str_data.startswith(","):
|
||||||
|
str_data = f"{{{str_data[1:]}"
|
||||||
# parse the json
|
# parse the json
|
||||||
parsed_data = json.loads(str_data)
|
parsed_data = json.loads(str_data)
|
||||||
# handle bad json
|
# handle bad json
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ class BMMinerAPI(BaseMinerAPI):
|
|||||||
:return: A confirmation of adding the pool.
|
:return: A confirmation of adding the pool.
|
||||||
"""
|
"""
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"addpool", parameters=f"{url}, " f"{username}, " f"{password}"
|
"addpool", parameters=f"{url},{username},{password}"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def poolpriority(self, *n: int) -> dict:
|
async def poolpriority(self, *n: int) -> dict:
|
||||||
@@ -147,7 +147,7 @@ class BMMinerAPI(BaseMinerAPI):
|
|||||||
|
|
||||||
:return: A confirmation of setting pool quota.
|
:return: A confirmation of setting pool quota.
|
||||||
"""
|
"""
|
||||||
return await self.send_command("poolquota", parameters=f"{n}, " f"{q}")
|
return await self.send_command("poolquota", parameters=f"{n},{q}")
|
||||||
|
|
||||||
async def disablepool(self, n: int) -> dict:
|
async def disablepool(self, n: int) -> dict:
|
||||||
"""Disable a pool.
|
"""Disable a pool.
|
||||||
@@ -326,7 +326,7 @@ class BMMinerAPI(BaseMinerAPI):
|
|||||||
|
|
||||||
:return: The results of setting config of name to n.
|
:return: The results of setting config of name to n.
|
||||||
"""
|
"""
|
||||||
return await self.send_command("setconfig", parameters=f"{name}, " f"{n}")
|
return await self.send_command("setconfig", parameters=f"{name},{n}")
|
||||||
|
|
||||||
async def usbstats(self) -> dict:
|
async def usbstats(self) -> dict:
|
||||||
"""Get stats of all USB devices except ztex.
|
"""Get stats of all USB devices except ztex.
|
||||||
@@ -354,11 +354,9 @@ class BMMinerAPI(BaseMinerAPI):
|
|||||||
:return: Confirmation of setting PGA n with opt[,val].
|
:return: Confirmation of setting PGA n with opt[,val].
|
||||||
"""
|
"""
|
||||||
if val:
|
if val:
|
||||||
return await self.send_command(
|
return await self.send_command("pgaset", parameters=f"{n},{opt},{val}")
|
||||||
"pgaset", parameters=f"{n}, " f"{opt}, " f"{val}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return await self.send_command("pgaset", parameters=f"{n}, " f"{opt}")
|
return await self.send_command("pgaset", parameters=f"{n},{opt}")
|
||||||
|
|
||||||
async def zero(self, which: str, summary: bool) -> dict:
|
async def zero(self, which: str, summary: bool) -> dict:
|
||||||
"""Zero a device.
|
"""Zero a device.
|
||||||
@@ -373,7 +371,7 @@ class BMMinerAPI(BaseMinerAPI):
|
|||||||
:return: the STATUS section with info on the zero and optional
|
:return: the STATUS section with info on the zero and optional
|
||||||
summary.
|
summary.
|
||||||
"""
|
"""
|
||||||
return await self.send_command("zero", parameters=f"{which}, {summary}")
|
return await self.send_command("zero", parameters=f"{which},{summary}")
|
||||||
|
|
||||||
async def hotplug(self, n: int) -> dict:
|
async def hotplug(self, n: int) -> dict:
|
||||||
"""Enable hotplug.
|
"""Enable hotplug.
|
||||||
@@ -474,9 +472,9 @@ class BMMinerAPI(BaseMinerAPI):
|
|||||||
:return: Confirmation of setting option opt to value val.
|
:return: Confirmation of setting option opt to value val.
|
||||||
"""
|
"""
|
||||||
if val:
|
if val:
|
||||||
return await self.send_command("ascset", parameters=f"{n}, {opt}, {val}")
|
return await self.send_command("ascset", parameters=f"{n},{opt},{val}")
|
||||||
else:
|
else:
|
||||||
return await self.send_command("ascset", parameters=f"{n}, {opt}")
|
return await self.send_command("ascset", parameters=f"{n},{opt}")
|
||||||
|
|
||||||
async def lcd(self) -> dict:
|
async def lcd(self) -> dict:
|
||||||
"""Get a general all-in-one status summary of the miner.
|
"""Get a general all-in-one status summary of the miner.
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ class BOSMinerAPI(BaseMinerAPI):
|
|||||||
async def addpool(self, url: str, username: str, password: str) -> dict:
|
async def addpool(self, url: str, username: str, password: str) -> dict:
|
||||||
# BOS has not implemented this yet, they will in the future
|
# BOS has not implemented this yet, they will in the future
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
# return await self.send_command("addpool", parameters=f"{url}, {username}, {password}")
|
# return await self.send_command("addpool", parameters=f"{url},{username},{password}")
|
||||||
|
|
||||||
async def removepool(self, n: int) -> dict:
|
async def removepool(self, n: int) -> dict:
|
||||||
# BOS has not implemented this yet, they will in the future
|
# BOS has not implemented this yet, they will in the future
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class CGMinerAPI(BaseMinerAPI):
|
|||||||
:return: A confirmation of adding the pool.
|
:return: A confirmation of adding the pool.
|
||||||
"""
|
"""
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"addpool", parameters=f"{url}, " f"{username}, " f"{password}"
|
"addpool", parameters=f"{url},{username},{password}"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def poolpriority(self, *n: int) -> dict:
|
async def poolpriority(self, *n: int) -> dict:
|
||||||
@@ -143,7 +143,7 @@ class CGMinerAPI(BaseMinerAPI):
|
|||||||
|
|
||||||
:return: A confirmation of setting pool quota.
|
:return: A confirmation of setting pool quota.
|
||||||
"""
|
"""
|
||||||
return await self.send_command("poolquota", parameters=f"{n}, " f"{q}")
|
return await self.send_command("poolquota", parameters=f"{n},{q}")
|
||||||
|
|
||||||
async def disablepool(self, n: int) -> dict:
|
async def disablepool(self, n: int) -> dict:
|
||||||
"""Disable a pool.
|
"""Disable a pool.
|
||||||
@@ -322,7 +322,7 @@ class CGMinerAPI(BaseMinerAPI):
|
|||||||
|
|
||||||
:return: The results of setting config of name to n.
|
:return: The results of setting config of name to n.
|
||||||
"""
|
"""
|
||||||
return await self.send_command("setconfig", parameters=f"{name}, " f"{n}")
|
return await self.send_command("setconfig", parameters=f"{name},{n}")
|
||||||
|
|
||||||
async def usbstats(self) -> dict:
|
async def usbstats(self) -> dict:
|
||||||
"""Get stats of all USB devices except ztex.
|
"""Get stats of all USB devices except ztex.
|
||||||
@@ -350,11 +350,9 @@ class CGMinerAPI(BaseMinerAPI):
|
|||||||
:return: Confirmation of setting PGA n with opt[,val].
|
:return: Confirmation of setting PGA n with opt[,val].
|
||||||
"""
|
"""
|
||||||
if val:
|
if val:
|
||||||
return await self.send_command(
|
return await self.send_command("pgaset", parameters=f"{n},{opt},{val}")
|
||||||
"pgaset", parameters=f"{n}, " f"{opt}, " f"{val}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return await self.send_command("pgaset", parameters=f"{n}, " f"{opt}")
|
return await self.send_command("pgaset", parameters=f"{n},{opt}")
|
||||||
|
|
||||||
async def zero(self, which: str, summary: bool) -> dict:
|
async def zero(self, which: str, summary: bool) -> dict:
|
||||||
"""Zero a device.
|
"""Zero a device.
|
||||||
@@ -369,7 +367,7 @@ class CGMinerAPI(BaseMinerAPI):
|
|||||||
:return: the STATUS section with info on the zero and optional
|
:return: the STATUS section with info on the zero and optional
|
||||||
summary.
|
summary.
|
||||||
"""
|
"""
|
||||||
return await self.send_command("zero", parameters=f"{which}, " f"{summary}")
|
return await self.send_command("zero", parameters=f"{which},{summary}")
|
||||||
|
|
||||||
async def hotplug(self, n: int) -> dict:
|
async def hotplug(self, n: int) -> dict:
|
||||||
"""Enable hotplug.
|
"""Enable hotplug.
|
||||||
@@ -470,11 +468,9 @@ class CGMinerAPI(BaseMinerAPI):
|
|||||||
:return: Confirmation of setting option opt to value val.
|
:return: Confirmation of setting option opt to value val.
|
||||||
"""
|
"""
|
||||||
if val:
|
if val:
|
||||||
return await self.send_command(
|
return await self.send_command("ascset", parameters=f"{n},{opt},{val}")
|
||||||
"ascset", parameters=f"{n}, " f"{opt}, " f"{val}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return await self.send_command("ascset", parameters=f"{n}, " f"{opt}")
|
return await self.send_command("ascset", parameters=f"{n},{opt}")
|
||||||
|
|
||||||
async def lcd(self) -> dict:
|
async def lcd(self) -> dict:
|
||||||
"""Get a general all-in-one status summary of the miner.
|
"""Get a general all-in-one status summary of the miner.
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class UnknownAPI(BaseMinerAPI):
|
|||||||
async def addpool(self, url: str, username: str, password: str) -> dict:
|
async def addpool(self, url: str, username: str, password: str) -> dict:
|
||||||
# BOS has not implemented this yet, they will in the future
|
# BOS has not implemented this yet, they will in the future
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
# return await self.send_command("addpool", parameters=f"{url}, {username}, {password}")
|
# return await self.send_command("addpool", parameters=f"{url},{username},{password}")
|
||||||
|
|
||||||
async def removepool(self, n: int) -> dict:
|
async def removepool(self, n: int) -> dict:
|
||||||
# BOS has not implemented this yet, they will in the future
|
# BOS has not implemented this yet, they will in the future
|
||||||
|
|||||||
29
README.md
29
README.md
@@ -9,7 +9,7 @@ For those of you who aren't comfortable with code and developer tools, there are
|
|||||||
*CFG Util is a GUI for interfacing with the miners easily, it is mostly self-explanatory.*
|
*CFG Util is a GUI for interfacing with the miners easily, it is mostly self-explanatory.*
|
||||||
|
|
||||||
To use CFG Util you have 2 options -
|
To use CFG Util you have 2 options -
|
||||||
1. Run it directly with the file ```config_tool.py``` or import it with ```from cfg_util import main```, then run the ```main()``` function in an asyncio event loop like -
|
1. Run it directly with the file ```config_tool.py``` or import it with ```from cfg_util import main```, then run the ```main()``` function like -
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tools.cfg_util import main
|
from tools.cfg_util import main
|
||||||
@@ -20,7 +20,7 @@ if __name__ == '__main__':
|
|||||||
2. Make a build of the CFG Util for your system using cx_freeze and ```make_cfg_tool_exe.py```
|
2. Make a build of the CFG Util for your system using cx_freeze and ```make_cfg_tool_exe.py```
|
||||||
(Alternatively, you can get a build made by me here -> https://drive.google.com/drive/folders/147vBXbuaX85inataXeSAiKk8IKf-7xtR)
|
(Alternatively, you can get a build made by me here -> https://drive.google.com/drive/folders/147vBXbuaX85inataXeSAiKk8IKf-7xtR)
|
||||||
1. Open either Command Prompt on Windows or Terminal on Mac or UNIX.
|
1. Open either Command Prompt on Windows or Terminal on Mac or UNIX.
|
||||||
2. Navigate to this directory, and run ```make_cfg_tool_exe.py build``` on Windows or ```python3 make_cfg_tool_exe.py``` on Mac or UNIX.
|
2. Navigate to this directory, and run ```make_cfg_tool_exe.py build``` on Windows or ```python3 make_cfg_tool_exe.py build``` on Mac or UNIX.
|
||||||
|
|
||||||
### Interfacing with miners programmatically
|
### Interfacing with miners programmatically
|
||||||
<br>
|
<br>
|
||||||
@@ -48,7 +48,6 @@ A basic script to find all miners on the network and get the hashrate from them
|
|||||||
```python
|
```python
|
||||||
import asyncio
|
import asyncio
|
||||||
from network import MinerNetwork
|
from network import MinerNetwork
|
||||||
from tools.cfg_util_old.func.parse_data import safe_parse_api_data
|
|
||||||
|
|
||||||
|
|
||||||
async def get_hashrate():
|
async def get_hashrate():
|
||||||
@@ -60,18 +59,11 @@ async def get_hashrate():
|
|||||||
# Miner Network scan function returns Miner classes for all miners found
|
# Miner Network scan function returns Miner classes for all miners found
|
||||||
miners = await miner_network.scan_network_for_miners()
|
miners = await miner_network.scan_network_for_miners()
|
||||||
# Each miner will return with its own set of functions, and an API class instance
|
# Each miner will return with its own set of functions, and an API class instance
|
||||||
tasks = [miner.api.summary() for miner in miners]
|
tasks = [miner.get_data() for miner in miners]
|
||||||
# Gather all tasks asynchronously and run them
|
# Gather all tasks asynchronously and run them
|
||||||
data = await asyncio.gather(*tasks)
|
data = await asyncio.gather(*tasks)
|
||||||
parse_tasks = []
|
# now we have a list of MinerData, and can get .hashrate
|
||||||
for item in data:
|
print([item.hashrate for item in data])
|
||||||
# safe_parse_api_data parses the data from a miner API
|
|
||||||
# It will raise an APIError (from API import APIError) if there is a problem
|
|
||||||
parse_tasks.append(safe_parse_api_data(item, 'SUMMARY', 0, 'MHS 5s'))
|
|
||||||
# Gather all tasks asynchronously and run them
|
|
||||||
data = await asyncio.gather(*parse_tasks)
|
|
||||||
# Print a list of all the hashrates
|
|
||||||
print(data)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -84,7 +76,7 @@ You can also create your own miner without scanning if you know the IP:
|
|||||||
import asyncio
|
import asyncio
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from miners.miner_factory import MinerFactory
|
from miners.miner_factory import MinerFactory
|
||||||
from tools.cfg_util_old.func.parse_data import safe_parse_api_data
|
|
||||||
|
|
||||||
|
|
||||||
async def get_miner_hashrate(ip: str):
|
async def get_miner_hashrate(ip: str):
|
||||||
@@ -95,11 +87,9 @@ async def get_miner_hashrate(ip: str):
|
|||||||
# Wait for the factory to return the miner
|
# Wait for the factory to return the miner
|
||||||
miner = await miner_factory.get_miner(miner_ip)
|
miner = await miner_factory.get_miner(miner_ip)
|
||||||
# Get the API data
|
# Get the API data
|
||||||
summary = await miner.api.summary()
|
data = await miner.get_data()
|
||||||
# safe_parse_api_data parses the data from a miner API
|
# print out hashrate
|
||||||
# It will raise an APIError (from API import APIError) if there is a problem
|
print(data.hashrate)
|
||||||
data = await safe_parse_api_data(summary, 'SUMMARY', 0, 'MHS 5s')
|
|
||||||
print(data)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -112,6 +102,7 @@ Now that you know that, lets move on to some common API functions that you might
|
|||||||
|
|
||||||
### Common commands:
|
### Common commands:
|
||||||
* Get the data used by the config utility, this includes pool data, wattage use, temperature, hashrate, etc:
|
* Get the data used by the config utility, this includes pool data, wattage use, temperature, hashrate, etc:
|
||||||
|
* All the data from below commands and more are returned from this in a consistent dataclass. Check out the `MinerData` class in `/data/__init__.py` for more information.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|||||||
@@ -1,88 +1,366 @@
|
|||||||
"""
|
from dataclasses import dataclass, asdict
|
||||||
SAMPLE CONFIG
|
from typing import List, Literal
|
||||||
-------------------
|
import random
|
||||||
{
|
import string
|
||||||
"format": {
|
|
||||||
"version": "1.2+", # -> (default = "1.2+", str, (bos: format.version))
|
import toml
|
||||||
"model": "Antminer S9", # -> (default = "Antminer S9", str, (bos: format.model))
|
import yaml
|
||||||
"generator": "upstream_config_util", # -> (hidden, always = "upstream_config_util", str, (bos: format.generator))
|
import json
|
||||||
"timestamp": 1606842000, # -> (hidden, always = int(time.time()) (current unix time), int, (bos: format.timestamp))
|
import time
|
||||||
},
|
|
||||||
"temperature": {
|
|
||||||
"mode": "auto", # -> (default = "auto", str["auto", "manual", "disabled"], (bos: temp_control.mode))
|
|
||||||
"target": 70.0, # -> (default = 70.0, float, (bos: temp_control.target_temp))
|
|
||||||
"hot": 80.0, # -> (default = 80.0, float, (bos: temp_control.hot_temp))
|
|
||||||
"danger": 90.0, # -> (default = 90.0, float, (bos: temp_control.dangerous_temp))
|
|
||||||
},
|
|
||||||
"fans": { # -> (optional, required if temperature["mode"] == "disabled", (bos: fan_control))
|
|
||||||
"min_fans": 1, # -> (default = 1, int, (bos: fan_control.min_fans))
|
|
||||||
"speed": 100, # -> (default = 100, 0 < int < 100, (bos: fan_control.speed))
|
|
||||||
},
|
|
||||||
"asicboost": True, # -> (default = True, bool, (bos : hash_chain_global.asic_boost))
|
|
||||||
"pool_groups": [
|
|
||||||
{
|
|
||||||
"group_name": "Upstream", # -> (default = "group_{index}" (group_0), str, (bos: group.[index].name))
|
|
||||||
"quota": 1, # -> (default = 1, int, (bos: group.[index].quota))
|
|
||||||
"pools": [
|
|
||||||
{
|
|
||||||
"url": "stratum+tcp://stratum.slushpool.com:3333", # -> (str, (bos: group.[index].pool.[index].url))
|
|
||||||
"username": "UpstreamDataInc.test", # -> (str, (bos: group.[index].pool.[index].user))
|
|
||||||
"password": "123", # -> (str, (bos: group.[index].pool.[index].password))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "stratum+tcp://us-east.stratum.slushpool.com:3333", # -> (str, (bos: group.[index].pool.[index].url))
|
|
||||||
"username": "UpstreamDataInc.test", # -> (str, (bos: group.[index].pool.[index].user))
|
|
||||||
"password": "123", # -> (str, (bos: group.[index].pool.[index].password))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "stratum+tcp://ca.stratum.slushpool.com:3333", # -> (str, (bos: group.[index].pool.[index].url))
|
|
||||||
"username": "UpstreamDataInc.test", # -> (str, (bos: group.[index].pool.[index].user))
|
|
||||||
"password": "123", # -> (str, (bos: group.[index].pool.[index].password))
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_name": "Upstream2", # -> (default = "group_{index}" (group_1), str, (bos: group.[index].name))
|
|
||||||
"quota": 4, # -> (default = 1, int, (bos: group.[index].quota))
|
|
||||||
"pools": [
|
|
||||||
{
|
|
||||||
"url": "stratum+tcp://stratum.slushpool.com:3333", # -> (str, (bos: group.[index].pool.[index].url))
|
|
||||||
"username": "UpstreamDataTesting.test", # -> (str, (bos: group.[index].pool.[index].user))
|
|
||||||
"password": "123", # -> (str, (bos: group.[index].pool.[index].password))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "stratum+tcp://us-east.stratum.slushpool.com:3333", # -> (str, (bos: group.[index].pool.[index].url))
|
|
||||||
"username": "UpstreamDataTesting.test", # -> (str, (bos: group.[index].pool.[index].user))
|
|
||||||
"password": "123", # -> (str, (bos: group.[index].pool.[index].password))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "stratum+tcp://ca.stratum.slushpool.com:3333", # -> (str, (bos: group.[index].pool.[index].url))
|
|
||||||
"username": "UpstreamDataTesting.test", # -> (str, (bos: group.[index].pool.[index].user))
|
|
||||||
"password": "123", # -> (str, (bos: group.[index].pool.[index].password))
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"autotuning": {
|
|
||||||
"enabled": True, # -> (default = True, bool), (bos: autotuning.enabled)
|
|
||||||
"wattage": 900, # -> (default = 900, int, (bos: autotuning.psu_power_limit))
|
|
||||||
},
|
|
||||||
"power_scaling": {
|
|
||||||
"enabled": False, # -> (default = False, bool, (bos: power_scaling.enabled))
|
|
||||||
"power_step": 100, # -> (default = 100, int, (bos: power_scaling.power_step))
|
|
||||||
"min_psu_power_limit": 800, # -> (default = 800, int, (bos: power_scaling.min_psu_power_limit))
|
|
||||||
"shutdown_enabled": True, # -> (default = False, bool, (bos: power_scaling.shutdown_enabled))
|
|
||||||
"shutdown_duration": 3.0, # -> (default = 3.0, float, (bos: power_scaling.shutdown_duration))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def general_config_convert_pools(config: dict):
|
@dataclass
|
||||||
out_config = {}
|
class _Pool:
|
||||||
pools = config.get("pool_groups")
|
"""A dataclass for pool information.
|
||||||
if pools:
|
|
||||||
if len(pools) > 0:
|
:param url: URL of the pool.
|
||||||
pools = pools[0]
|
:param username: Username on the pool.
|
||||||
out_config = pools["pools"][:3]
|
:param password: Worker password on the pool.
|
||||||
return out_config
|
"""
|
||||||
|
|
||||||
|
url: str = ""
|
||||||
|
username: str = ""
|
||||||
|
password: str = ""
|
||||||
|
|
||||||
|
def from_dict(self, data: dict):
|
||||||
|
"""Convert raw pool data as a dict to usable data and save it to this class.
|
||||||
|
|
||||||
|
:param data: The raw config data to convert.
|
||||||
|
"""
|
||||||
|
for key in data.keys():
|
||||||
|
if key == "url":
|
||||||
|
self.url = data[key]
|
||||||
|
if key in ["user", "username"]:
|
||||||
|
self.username = data[key]
|
||||||
|
if key in ["pass", "password"]:
|
||||||
|
self.password = data[key]
|
||||||
|
return self
|
||||||
|
|
||||||
|
def as_x19(self, user_suffix: str = None):
|
||||||
|
"""Convert the data in this class to a dict usable by an X19 device.
|
||||||
|
|
||||||
|
:param user_suffix: The suffix to append to username.
|
||||||
|
"""
|
||||||
|
username = self.username
|
||||||
|
if user_suffix:
|
||||||
|
username = f"{username}{user_suffix}"
|
||||||
|
|
||||||
|
pool = {"url": self.url, "user": username, "pass": self.password}
|
||||||
|
return pool
|
||||||
|
|
||||||
|
def as_avalon(self, user_suffix: str = None):
|
||||||
|
username = self.username
|
||||||
|
if user_suffix:
|
||||||
|
username = f"{username}{user_suffix}"
|
||||||
|
|
||||||
|
pool = ",".join([self.url, username, self.password])
|
||||||
|
return pool
|
||||||
|
|
||||||
|
def as_bos(self, user_suffix: str = None):
|
||||||
|
"""Convert the data in this class to a dict usable by an BOSMiner device.
|
||||||
|
|
||||||
|
:param user_suffix: The suffix to append to username.
|
||||||
|
"""
|
||||||
|
username = self.username
|
||||||
|
if user_suffix:
|
||||||
|
username = f"{username}{user_suffix}"
|
||||||
|
|
||||||
|
pool = {"url": self.url, "user": username, "password": self.password}
|
||||||
|
return pool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class _PoolGroup:
|
||||||
|
"""A dataclass for pool group information.
|
||||||
|
|
||||||
|
:param quota: The group quota.
|
||||||
|
:param group_name: The name of the pool group.
|
||||||
|
:param pools: A list of pools in this group.
|
||||||
|
"""
|
||||||
|
|
||||||
|
quota: int = 1
|
||||||
|
group_name: str = None
|
||||||
|
pools: List[_Pool] = None
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if not self.group_name:
|
||||||
|
self.group_name = "".join(
|
||||||
|
random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
|
||||||
|
) # generate random pool group name in case it isn't set
|
||||||
|
|
||||||
|
def from_dict(self, data: dict):
|
||||||
|
"""Convert raw pool group data as a dict to usable data and save it to this class.
|
||||||
|
|
||||||
|
:param data: The raw config data to convert.
|
||||||
|
"""
|
||||||
|
pools = []
|
||||||
|
for key in data.keys():
|
||||||
|
if key in ["name", "group_name"]:
|
||||||
|
self.group_name = data[key]
|
||||||
|
if key == "quota":
|
||||||
|
self.quota = data[key]
|
||||||
|
if key in ["pools", "pool"]:
|
||||||
|
for pool in data[key]:
|
||||||
|
pools.append(_Pool().from_dict(pool))
|
||||||
|
self.pools = pools
|
||||||
|
return self
|
||||||
|
|
||||||
|
def as_x19(self, user_suffix: str = None):
|
||||||
|
"""Convert the data in this class to a dict usable by an X19 device.
|
||||||
|
|
||||||
|
:param user_suffix: The suffix to append to username.
|
||||||
|
"""
|
||||||
|
pools = []
|
||||||
|
for pool in self.pools[:3]:
|
||||||
|
pools.append(pool.as_x19(user_suffix=user_suffix))
|
||||||
|
return pools
|
||||||
|
|
||||||
|
def as_avalon(self, user_suffix: str = None):
|
||||||
|
pool = self.pools[0].as_avalon(user_suffix=user_suffix)
|
||||||
|
return pool
|
||||||
|
|
||||||
|
def as_bos(self, user_suffix: str = None):
|
||||||
|
"""Convert the data in this class to a dict usable by an BOSMiner device.
|
||||||
|
|
||||||
|
:param user_suffix: The suffix to append to username.
|
||||||
|
"""
|
||||||
|
group = {
|
||||||
|
"name": self.group_name,
|
||||||
|
"quota": self.quota,
|
||||||
|
"pool": [pool.as_bos(user_suffix=user_suffix) for pool in self.pools],
|
||||||
|
}
|
||||||
|
return group
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MinerConfig:
|
||||||
|
"""A dataclass for miner configuration information.
|
||||||
|
|
||||||
|
:param pool_groups: A list of pool groups in this config.
|
||||||
|
:param temp_mode: The temperature control mode.
|
||||||
|
:param temp_target: The target temp.
|
||||||
|
:param temp_hot: The hot temp (100% fans).
|
||||||
|
:param temp_dangerous: The dangerous temp (shutdown).
|
||||||
|
:param minimum_fans: The minimum numbers of fans to run the miner.
|
||||||
|
:param fan_speed: Manual fan speed to run the fan at (only if temp_mode == "manual").
|
||||||
|
:param asicboost: Whether or not to enable asicboost.
|
||||||
|
:param autotuning_enabled: Whether or not to enable autotuning.
|
||||||
|
:param autotuning_wattage: The wattage to use when autotuning.
|
||||||
|
:param dps_enabled: Whether or not to enable dynamic power scaling.
|
||||||
|
:param dps_power_step: The amount of power to reduce autotuning by when the miner reaches dangerous temp.
|
||||||
|
:param dps_min_power: The minimum power to reduce autotuning to.
|
||||||
|
:param dps_shutdown_enabled: Whether or not to shutdown the miner when `dps_min_power` is reached.
|
||||||
|
:param dps_shutdown_duration: The amount of time to shutdown for (in hours).
|
||||||
|
"""
|
||||||
|
|
||||||
|
pool_groups: List[_PoolGroup] = None
|
||||||
|
|
||||||
|
temp_mode: Literal["auto", "manual", "disabled"] = "auto"
|
||||||
|
temp_target: float = 70.0
|
||||||
|
temp_hot: float = 80.0
|
||||||
|
temp_dangerous: float = 10.0
|
||||||
|
|
||||||
|
minimum_fans: int = None
|
||||||
|
fan_speed: Literal[tuple(range(101))] = None # noqa - Ignore weird Literal usage
|
||||||
|
|
||||||
|
asicboost: bool = None
|
||||||
|
|
||||||
|
autotuning_enabled: bool = True
|
||||||
|
autotuning_wattage: int = 900
|
||||||
|
|
||||||
|
dps_enabled: bool = None
|
||||||
|
dps_power_step: int = None
|
||||||
|
dps_min_power: int = None
|
||||||
|
dps_shutdown_enabled: bool = None
|
||||||
|
dps_shutdown_duration: float = None
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
"""Convert the data in this class to a dict."""
|
||||||
|
|
||||||
|
data_dict = asdict(self)
|
||||||
|
for key in asdict(self).keys():
|
||||||
|
if data_dict[key] is None:
|
||||||
|
del data_dict[key]
|
||||||
|
return data_dict
|
||||||
|
|
||||||
|
def as_toml(self):
|
||||||
|
"""Convert the data in this class to toml."""
|
||||||
|
return toml.dumps(self.as_dict())
|
||||||
|
|
||||||
|
def as_yaml(self):
|
||||||
|
"""Convert the data in this class to yaml."""
|
||||||
|
return yaml.dump(self.as_dict(), sort_keys=False)
|
||||||
|
|
||||||
|
def from_raw(self, data: dict):
|
||||||
|
"""Convert raw config data as a dict to usable data and save it to this class.
|
||||||
|
|
||||||
|
:param data: The raw config data to convert.
|
||||||
|
"""
|
||||||
|
pool_groups = []
|
||||||
|
for key in data.keys():
|
||||||
|
if key == "pools":
|
||||||
|
pool_groups.append(_PoolGroup().from_dict({"pools": data[key]}))
|
||||||
|
elif key == "group":
|
||||||
|
for group in data[key]:
|
||||||
|
pool_groups.append(_PoolGroup().from_dict(group))
|
||||||
|
|
||||||
|
if key == "bitmain-fan-ctrl":
|
||||||
|
if data[key]:
|
||||||
|
self.temp_mode = "manual"
|
||||||
|
if data.get("bitmain-fan-pwm"):
|
||||||
|
self.fan_speed = int(data["bitmain-fan-pwm"])
|
||||||
|
elif key == "fan_control":
|
||||||
|
for _key in data[key].keys():
|
||||||
|
if _key == "min_fans":
|
||||||
|
self.minimum_fans = data[key][_key]
|
||||||
|
elif _key == "speed":
|
||||||
|
self.fan_speed = data[key][_key]
|
||||||
|
elif key == "temp_control":
|
||||||
|
for _key in data[key].keys():
|
||||||
|
if _key == "mode":
|
||||||
|
self.temp_mode = data[key][_key]
|
||||||
|
elif _key == "target_temp":
|
||||||
|
self.temp_target = data[key][_key]
|
||||||
|
elif _key == "hot_temp":
|
||||||
|
self.temp_hot = data[key][_key]
|
||||||
|
elif _key == "dangerous_temp":
|
||||||
|
self.temp_dangerous = data[key][_key]
|
||||||
|
|
||||||
|
if key == "hash_chain_global":
|
||||||
|
if data[key].get("asic_boost"):
|
||||||
|
self.asicboost = data[key]["asic_boost"]
|
||||||
|
|
||||||
|
if key == "autotuning":
|
||||||
|
for _key in data[key].keys():
|
||||||
|
if _key == "enabled":
|
||||||
|
self.autotuning_enabled = data[key][_key]
|
||||||
|
elif _key == "psu_power_limit":
|
||||||
|
self.autotuning_wattage = data[key][_key]
|
||||||
|
|
||||||
|
if key == "power_scaling":
|
||||||
|
for _key in data[key].keys():
|
||||||
|
if _key == "enabled":
|
||||||
|
self.dps_enabled = data[key][_key]
|
||||||
|
elif _key == "power_step":
|
||||||
|
self.dps_power_step = data[key][_key]
|
||||||
|
elif _key == "min_psu_power_limit":
|
||||||
|
self.dps_min_power = data[key][_key]
|
||||||
|
elif _key == "shutdown_enabled":
|
||||||
|
self.dps_shutdown_enabled = data[key][_key]
|
||||||
|
elif _key == "shutdown_duration":
|
||||||
|
self.dps_shutdown_duration = data[key][_key]
|
||||||
|
|
||||||
|
self.pool_groups = pool_groups
|
||||||
|
return self
|
||||||
|
|
||||||
|
def from_dict(self, data: dict):
|
||||||
|
"""Convert an output dict of this class back into usable data and save it to this class.
|
||||||
|
|
||||||
|
:param data: The raw config data to convert.
|
||||||
|
"""
|
||||||
|
pool_groups = []
|
||||||
|
for group in data["pool_groups"]:
|
||||||
|
pool_groups.append(_PoolGroup().from_dict(group))
|
||||||
|
for key in data.keys():
|
||||||
|
if getattr(self, key) and not key == "pool_groups":
|
||||||
|
setattr(self, key, data[key])
|
||||||
|
self.pool_groups = pool_groups
|
||||||
|
return self
|
||||||
|
|
||||||
|
def from_toml(self, data: str):
|
||||||
|
"""Convert output toml of this class back into usable data and save it to this class.
|
||||||
|
|
||||||
|
:param data: The raw config data to convert.
|
||||||
|
"""
|
||||||
|
return self.from_dict(toml.loads(data))
|
||||||
|
|
||||||
|
def from_yaml(self, data: str):
|
||||||
|
"""Convert output yaml of this class back into usable data and save it to this class.
|
||||||
|
|
||||||
|
:param data: The raw config data to convert.
|
||||||
|
"""
|
||||||
|
return self.from_dict(yaml.load(data, Loader=yaml.SafeLoader))
|
||||||
|
|
||||||
|
def as_x19(self, user_suffix: str = None) -> str:
|
||||||
|
"""Convert the data in this class to a config usable by an X19 device.
|
||||||
|
|
||||||
|
:param user_suffix: The suffix to append to username.
|
||||||
|
"""
|
||||||
|
cfg = {
|
||||||
|
"pools": self.pool_groups[0].as_x19(user_suffix=user_suffix),
|
||||||
|
"bitmain-fan-ctrl": False,
|
||||||
|
"bitmain-fan-pwn": 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
if not self.temp_mode == "auto":
|
||||||
|
cfg["bitmain-fan-ctrl"] = True
|
||||||
|
|
||||||
|
if self.fan_speed:
|
||||||
|
cfg["bitmain-fan-ctrl"] = str(self.fan_speed)
|
||||||
|
|
||||||
|
return json.dumps(cfg)
|
||||||
|
|
||||||
|
def as_avalon(self, user_suffix: str = None) -> str:
|
||||||
|
cfg = self.pool_groups[0].as_avalon()
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def as_bos(self, model: str = "S9", user_suffix: str = None) -> str:
|
||||||
|
"""Convert the data in this class to a config usable by an BOSMiner device.
|
||||||
|
|
||||||
|
:param model: The model of the miner to be used in the format portion of the config.
|
||||||
|
:param user_suffix: The suffix to append to username.
|
||||||
|
"""
|
||||||
|
cfg = {
|
||||||
|
"format": {
|
||||||
|
"version": "1.2+",
|
||||||
|
"model": f"Antminer {model}",
|
||||||
|
"generator": "Upstream Config Utility",
|
||||||
|
"timestamp": int(time.time()),
|
||||||
|
},
|
||||||
|
"group": [
|
||||||
|
group.as_bos(user_suffix=user_suffix) for group in self.pool_groups
|
||||||
|
],
|
||||||
|
"temp_control": {
|
||||||
|
"mode": self.temp_mode,
|
||||||
|
"target_temp": self.temp_target,
|
||||||
|
"hot_temp": self.temp_hot,
|
||||||
|
"dangerous_temp": self.temp_dangerous,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.autotuning_enabled or self.autotuning_wattage:
|
||||||
|
cfg["autotuning"] = {}
|
||||||
|
if self.autotuning_enabled:
|
||||||
|
cfg["autotuning"]["enabled"] = self.autotuning_enabled
|
||||||
|
if self.autotuning_wattage:
|
||||||
|
cfg["autotuning"]["psu_power_limit"] = self.autotuning_wattage
|
||||||
|
|
||||||
|
if self.asicboost:
|
||||||
|
cfg["hash_chain_global"] = {}
|
||||||
|
cfg["hash_chain_global"]["asic_boost"] = self.asicboost
|
||||||
|
|
||||||
|
if any(
|
||||||
|
[
|
||||||
|
getattr(self, item)
|
||||||
|
for item in [
|
||||||
|
"dps_enabled",
|
||||||
|
"dps_power_step",
|
||||||
|
"dps_min_power",
|
||||||
|
"dps_shutdown_enabled",
|
||||||
|
"dps_shutdown_duration",
|
||||||
|
]
|
||||||
|
]
|
||||||
|
):
|
||||||
|
cfg["power_scaling"] = {}
|
||||||
|
if self.dps_enabled:
|
||||||
|
cfg["power_scaling"]["enabled"] = self.dps_enabled
|
||||||
|
if self.dps_power_step:
|
||||||
|
cfg["power_scaling"]["power_step"] = self.dps_power_step
|
||||||
|
if self.dps_min_power:
|
||||||
|
cfg["power_scaling"]["min_psu_power_limit"] = self.dps_min_power
|
||||||
|
if self.dps_shutdown_enabled:
|
||||||
|
cfg["power_scaling"]["shutdown_enabled"] = self.dps_shutdown_enabled
|
||||||
|
if self.dps_shutdown_duration:
|
||||||
|
cfg["power_scaling"]["shutdown_duration"] = self.dps_shutdown_duration
|
||||||
|
|
||||||
|
return toml.dumps(cfg)
|
||||||
|
|||||||
221
config/bos.py
221
config/bos.py
@@ -1,221 +0,0 @@
|
|||||||
import time
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
|
|
||||||
def bos_config_convert(config: dict):
|
|
||||||
out_config = {}
|
|
||||||
for opt in config:
|
|
||||||
if opt == "format":
|
|
||||||
out_config["format"] = config[opt]
|
|
||||||
out_config["format"]["generator"] = "upstream_config_util"
|
|
||||||
out_config["format"]["timestamp"] = int(time.time())
|
|
||||||
elif opt == "temp_control":
|
|
||||||
out_config["temperature"] = {}
|
|
||||||
if "mode" in config[opt].keys():
|
|
||||||
out_config["temperature"]["mode"] = config[opt]["mode"]
|
|
||||||
else:
|
|
||||||
out_config["temperature"]["mode"] = "auto"
|
|
||||||
|
|
||||||
if "target_temp" in config[opt].keys():
|
|
||||||
out_config["temperature"]["target"] = config[opt]["target_temp"]
|
|
||||||
else:
|
|
||||||
out_config["temperature"]["target"] = 70.0
|
|
||||||
|
|
||||||
if "hot_temp" in config[opt].keys():
|
|
||||||
out_config["temperature"]["hot"] = config[opt]["hot_temp"]
|
|
||||||
else:
|
|
||||||
out_config["temperature"]["hot"] = 80.0
|
|
||||||
|
|
||||||
if "dangerous_temp" in config[opt].keys():
|
|
||||||
out_config["temperature"]["danger"] = config[opt]["dangerous_temp"]
|
|
||||||
else:
|
|
||||||
out_config["temperature"]["danger"] = 90.0
|
|
||||||
elif opt == "fan_control":
|
|
||||||
out_config["fans"] = {}
|
|
||||||
if "min_fans" in config[opt].keys():
|
|
||||||
out_config["fans"]["min_fans"] = config[opt]["min_fans"]
|
|
||||||
else:
|
|
||||||
out_config["fans"]["min_fans"] = 1
|
|
||||||
if "speed" in config[opt].keys():
|
|
||||||
out_config["fans"]["speed"] = config[opt]["speed"]
|
|
||||||
else:
|
|
||||||
out_config["fans"]["speed"] = 100
|
|
||||||
elif opt == "group":
|
|
||||||
out_config["pool_groups"] = [{} for _item in range(len(config[opt]))]
|
|
||||||
for idx in range(len(config[opt])):
|
|
||||||
out_config["pool_groups"][idx]["pools"] = []
|
|
||||||
out_config["pool_groups"][idx] = {}
|
|
||||||
if "name" in config[opt][idx].keys():
|
|
||||||
out_config["pool_groups"][idx]["group_name"] = config[opt][idx][
|
|
||||||
"name"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
out_config["pool_groups"][idx]["group_name"] = f"group_{idx}"
|
|
||||||
if "quota" in config[opt][idx].keys():
|
|
||||||
out_config["pool_groups"][idx]["quota"] = config[opt][idx]["quota"]
|
|
||||||
else:
|
|
||||||
out_config["pool_groups"][idx]["quota"] = 1
|
|
||||||
out_config["pool_groups"][idx]["pools"] = [
|
|
||||||
{} for _item in range(len(config[opt][idx]["pool"]))
|
|
||||||
]
|
|
||||||
for pool_idx in range(len(config[opt][idx]["pool"])):
|
|
||||||
out_config["pool_groups"][idx]["pools"][pool_idx]["url"] = config[
|
|
||||||
opt
|
|
||||||
][idx]["pool"][pool_idx]["url"]
|
|
||||||
out_config["pool_groups"][idx]["pools"][pool_idx][
|
|
||||||
"username"
|
|
||||||
] = config[opt][idx]["pool"][pool_idx]["user"]
|
|
||||||
out_config["pool_groups"][idx]["pools"][pool_idx][
|
|
||||||
"password"
|
|
||||||
] = config[opt][idx]["pool"][pool_idx]["password"]
|
|
||||||
elif opt == "autotuning":
|
|
||||||
out_config["autotuning"] = {}
|
|
||||||
if "enabled" in config[opt].keys():
|
|
||||||
out_config["autotuning"]["enabled"] = config[opt]["enabled"]
|
|
||||||
else:
|
|
||||||
out_config["autotuning"]["enabled"] = True
|
|
||||||
if "psu_power_limit" in config[opt].keys():
|
|
||||||
out_config["autotuning"]["wattage"] = config[opt]["psu_power_limit"]
|
|
||||||
else:
|
|
||||||
out_config["autotuning"]["wattage"] = 900
|
|
||||||
elif opt == "power_scaling":
|
|
||||||
out_config["power_scaling"] = {}
|
|
||||||
if "enabled" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["enabled"] = config[opt]["enabled"]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["enabled"] = False
|
|
||||||
if "power_step" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["power_step"] = config[opt]["power_step"]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["power_step"] = 100
|
|
||||||
if "min_psu_power_limit" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["min_psu_power_limit"] = config[opt][
|
|
||||||
"min_psu_power_limit"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["min_psu_power_limit"] = 800
|
|
||||||
if "shutdown_enabled" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["shutdown_enabled"] = config[opt][
|
|
||||||
"shutdown_enabled"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["shutdown_enabled"] = False
|
|
||||||
if "shutdown_duration" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["shutdown_duration"] = config[opt][
|
|
||||||
"shutdown_duration"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["shutdown_duration"] = 3.0
|
|
||||||
return yaml.dump(out_config, sort_keys=False)
|
|
||||||
|
|
||||||
|
|
||||||
def general_config_convert_bos(yaml_config, user_suffix: str = None):
|
|
||||||
config = yaml.load(yaml_config, Loader=yaml.SafeLoader)
|
|
||||||
out_config = {}
|
|
||||||
for opt in config:
|
|
||||||
if opt == "format":
|
|
||||||
out_config["format"] = config[opt]
|
|
||||||
out_config["format"]["generator"] = "upstream_config_util"
|
|
||||||
out_config["format"]["timestamp"] = int(time.time())
|
|
||||||
elif opt == "temperature":
|
|
||||||
out_config["temp_control"] = {}
|
|
||||||
if "mode" in config[opt].keys():
|
|
||||||
out_config["temp_control"]["mode"] = config[opt]["mode"]
|
|
||||||
else:
|
|
||||||
out_config["temp_control"]["mode"] = "auto"
|
|
||||||
|
|
||||||
if "target" in config[opt].keys():
|
|
||||||
out_config["temp_control"]["target_temp"] = config[opt]["target"]
|
|
||||||
else:
|
|
||||||
out_config["temp_control"]["target_temp"] = 70.0
|
|
||||||
|
|
||||||
if "hot" in config[opt].keys():
|
|
||||||
out_config["temp_control"]["hot_temp"] = config[opt]["hot"]
|
|
||||||
else:
|
|
||||||
out_config["temp_control"]["hot_temp"] = 80.0
|
|
||||||
|
|
||||||
if "danger" in config[opt].keys():
|
|
||||||
out_config["temp_control"]["dangerous_temp"] = config[opt]["danger"]
|
|
||||||
else:
|
|
||||||
out_config["temp_control"]["dangerous_temp"] = 90.0
|
|
||||||
elif opt == "fans":
|
|
||||||
out_config["fan_control"] = {}
|
|
||||||
if "min_fans" in config[opt].keys():
|
|
||||||
out_config["fan_control"]["min_fans"] = config[opt]["min_fans"]
|
|
||||||
else:
|
|
||||||
out_config["fan_control"]["min_fans"] = 1
|
|
||||||
if "speed" in config[opt].keys():
|
|
||||||
out_config["fan_control"]["speed"] = config[opt]["speed"]
|
|
||||||
else:
|
|
||||||
out_config["fan_control"]["speed"] = 100
|
|
||||||
elif opt == "pool_groups":
|
|
||||||
out_config["group"] = [{} for _item in range(len(config[opt]))]
|
|
||||||
for idx in range(len(config[opt])):
|
|
||||||
out_config["group"][idx]["pools"] = []
|
|
||||||
out_config["group"][idx] = {}
|
|
||||||
if "group_name" in config[opt][idx].keys():
|
|
||||||
out_config["group"][idx]["name"] = config[opt][idx]["group_name"]
|
|
||||||
else:
|
|
||||||
out_config["group"][idx]["name"] = f"group_{idx}"
|
|
||||||
if "quota" in config[opt][idx].keys():
|
|
||||||
out_config["group"][idx]["quota"] = config[opt][idx]["quota"]
|
|
||||||
else:
|
|
||||||
out_config["group"][idx]["quota"] = 1
|
|
||||||
out_config["group"][idx]["pool"] = [
|
|
||||||
{} for _item in range(len(config[opt][idx]["pools"]))
|
|
||||||
]
|
|
||||||
for pool_idx in range(len(config[opt][idx]["pools"])):
|
|
||||||
out_config["group"][idx]["pool"][pool_idx]["url"] = config[opt][
|
|
||||||
idx
|
|
||||||
]["pools"][pool_idx]["url"]
|
|
||||||
username = config[opt][idx]["pools"][pool_idx]["username"]
|
|
||||||
if user_suffix:
|
|
||||||
if "." in username:
|
|
||||||
username = f"{username}x{user_suffix}"
|
|
||||||
else:
|
|
||||||
username = f"{username}.{user_suffix}"
|
|
||||||
out_config["group"][idx]["pool"][pool_idx]["user"] = username
|
|
||||||
|
|
||||||
out_config["group"][idx]["pool"][pool_idx]["password"] = config[
|
|
||||||
opt
|
|
||||||
][idx]["pools"][pool_idx]["password"]
|
|
||||||
elif opt == "autotuning":
|
|
||||||
out_config["autotuning"] = {}
|
|
||||||
if "enabled" in config[opt].keys():
|
|
||||||
out_config["autotuning"]["enabled"] = config[opt]["enabled"]
|
|
||||||
else:
|
|
||||||
out_config["autotuning"]["enabled"] = True
|
|
||||||
if "wattage" in config[opt].keys():
|
|
||||||
out_config["autotuning"]["psu_power_limit"] = config[opt]["wattage"]
|
|
||||||
else:
|
|
||||||
out_config["autotuning"]["psu_power_limit"] = 900
|
|
||||||
elif opt == "power_scaling":
|
|
||||||
out_config["power_scaling"] = {}
|
|
||||||
if "enabled" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["enabled"] = config[opt]["enabled"]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["enabled"] = False
|
|
||||||
if "power_step" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["power_step"] = config[opt]["power_step"]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["power_step"] = 100
|
|
||||||
if "min_psu_power_limit" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["min_psu_power_limit"] = config[opt][
|
|
||||||
"min_psu_power_limit"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["min_psu_power_limit"] = 800
|
|
||||||
if "shutdown_enabled" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["shutdown_enabled"] = config[opt][
|
|
||||||
"shutdown_enabled"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["shutdown_enabled"] = False
|
|
||||||
if "shutdown_duration" in config[opt].keys():
|
|
||||||
out_config["power_scaling"]["shutdown_duration"] = config[opt][
|
|
||||||
"shutdown_duration"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
out_config["power_scaling"]["shutdown_duration"] = 3.0
|
|
||||||
return out_config
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
config cgminer 'default'
|
|
||||||
option pool1pw 'x'
|
|
||||||
option pool2pw 'x'
|
|
||||||
option pool3pw 'x'
|
|
||||||
option voltage_level_offset '0'
|
|
||||||
option fan '10'
|
|
||||||
option api_allow 'W:0/0'
|
|
||||||
option power_mode 'balance'
|
|
||||||
option pool1url 'stratum+tcp://ca.stratum.slushpool.com:3333'
|
|
||||||
option pool1user 'poolacct.worker1'
|
|
||||||
option pool2url 'stratum+tcp://ca.stratum.slushpool.com:3333'
|
|
||||||
option pool2user 'poolacct.worker2'
|
|
||||||
option pool3url 'stratum+tcp://ca.stratum.slushpool.com:3333'
|
|
||||||
option pool3user 'poolacct.worker3'
|
|
||||||
option ntp_enable 'openwrt'
|
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@ class MinerData:
|
|||||||
hostname: str = "Unknown"
|
hostname: str = "Unknown"
|
||||||
hashrate: float = 0
|
hashrate: float = 0
|
||||||
temperature_avg: int = field(init=False)
|
temperature_avg: int = field(init=False)
|
||||||
|
env_temp: float = 0
|
||||||
left_board_temp: int = 0
|
left_board_temp: int = 0
|
||||||
left_board_chip_temp: int = 0
|
left_board_chip_temp: int = 0
|
||||||
center_board_temp: int = 0
|
center_board_temp: int = 0
|
||||||
@@ -100,7 +101,7 @@ class MinerData:
|
|||||||
self.center_board_chip_temp,
|
self.center_board_chip_temp,
|
||||||
self.right_board_chip_temp,
|
self.right_board_chip_temp,
|
||||||
]:
|
]:
|
||||||
if not temp == 0:
|
if temp and not temp == 0:
|
||||||
total_temp += temp
|
total_temp += temp
|
||||||
temp_count += 1
|
temp_count += 1
|
||||||
if not temp_count > 0:
|
if not temp_count > 0:
|
||||||
|
|||||||
Binary file not shown.
@@ -1,14 +1,21 @@
|
|||||||
import logging
|
import logging
|
||||||
from settings import DEBUG
|
from settings import DEBUG, LOGFILE
|
||||||
|
|
||||||
|
|
||||||
def init_logger():
|
def init_logger():
|
||||||
logging.basicConfig(
|
if LOGFILE:
|
||||||
# filename="logfile.txt",
|
logging.basicConfig(
|
||||||
# filemode="a",
|
filename="logfile.txt",
|
||||||
format="%(pathname)s:%(lineno)d in %(funcName)s\n[%(levelname)s][%(asctime)s](%(name)s) - %(message)s",
|
filemode="a",
|
||||||
datefmt="%x %X",
|
format="%(pathname)s:%(lineno)d in %(funcName)s\n[%(levelname)s][%(asctime)s](%(name)s) - %(message)s",
|
||||||
)
|
datefmt="%x %X",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logging.basicConfig(
|
||||||
|
format="%(pathname)s:%(lineno)d in %(funcName)s\n[%(levelname)s][%(asctime)s](%(name)s) - %(message)s",
|
||||||
|
datefmt="%x %X",
|
||||||
|
)
|
||||||
|
|
||||||
_logger = logging.getLogger()
|
_logger = logging.getLogger()
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import datetime
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from cx_Freeze import setup, Executable
|
from cx_Freeze import setup, Executable
|
||||||
|
from setuptools import find_packages
|
||||||
|
|
||||||
base = None
|
base = None
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
@@ -16,7 +17,6 @@ if sys.platform == "win32":
|
|||||||
|
|
||||||
version = datetime.datetime.now()
|
version = datetime.datetime.now()
|
||||||
version = version.strftime("%y.%m.%d")
|
version = version.strftime("%y.%m.%d")
|
||||||
print(version)
|
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
@@ -30,9 +30,7 @@ setup(
|
|||||||
os.path.join(os.getcwd(), "settings/settings.toml"),
|
os.path.join(os.getcwd(), "settings/settings.toml"),
|
||||||
os.path.join(os.getcwd(), "static/CFG-Util-README.md"),
|
os.path.join(os.getcwd(), "static/CFG-Util-README.md"),
|
||||||
],
|
],
|
||||||
"excludes": [
|
"excludes": ["tests", "tools.web_testbench", "tools.web_monitor"],
|
||||||
os.path.join(os.getcwd(), "tools/web_testbench/files"),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
executables=[
|
executables=[
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class BaseMiner:
|
|||||||
self.nominal_chips = 1
|
self.nominal_chips = 1
|
||||||
self.version = None
|
self.version = None
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
self.config = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{'' if not self.api_type else self.api_type} {'' if not self.model else self.model}: {str(self.ip)}"
|
return f"{'' if not self.api_type else self.api_type} {'' if not self.model else self.model}: {str(self.ip)}"
|
||||||
@@ -99,5 +100,5 @@ class BaseMiner:
|
|||||||
async def get_mac(self):
|
async def get_mac(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_data(self):
|
async def get_data(self) -> MinerData:
|
||||||
return MinerData(ip=str(self.ip))
|
return MinerData(ip=str(self.ip))
|
||||||
|
|||||||
@@ -203,11 +203,17 @@ class BMMiner(BaseMiner):
|
|||||||
)
|
)
|
||||||
|
|
||||||
board_map = {0: "left_board", 1: "center_board", 2: "right_board"}
|
board_map = {0: "left_board", 1: "center_board", 2: "right_board"}
|
||||||
|
env_temp_list = []
|
||||||
for item in range(3):
|
for item in range(3):
|
||||||
board_temp = temp[1].get(f"temp{item + board_offset}")
|
board_temp = temp[1].get(f"temp{item + board_offset}")
|
||||||
chip_temp = temp[1].get(f"temp2_{item + board_offset}")
|
chip_temp = temp[1].get(f"temp2_{item + board_offset}")
|
||||||
setattr(data, f"{board_map[item]}_chip_temp", chip_temp)
|
setattr(data, f"{board_map[item]}_chip_temp", chip_temp)
|
||||||
setattr(data, f"{board_map[item]}_temp", board_temp)
|
setattr(data, f"{board_map[item]}_temp", board_temp)
|
||||||
|
if f"temp_pcb{item}" in temp[1].keys():
|
||||||
|
env_temp = temp[1][f"temp_pcb{item}"].split("-")[0]
|
||||||
|
if not env_temp == 0:
|
||||||
|
env_temp_list.append(int(env_temp))
|
||||||
|
data.env_temp = sum(env_temp_list) / len(env_temp_list)
|
||||||
|
|
||||||
if pools:
|
if pools:
|
||||||
pool_1 = None
|
pool_1 = None
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from API import APIError
|
|||||||
|
|
||||||
from data import MinerData
|
from data import MinerData
|
||||||
|
|
||||||
from config.bos import bos_config_convert, general_config_convert_bos
|
from config import MinerConfig
|
||||||
|
|
||||||
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
|
||||||
@@ -102,8 +102,9 @@ class BOSMiner(BaseMiner):
|
|||||||
async with sftp.open("/etc/bosminer.toml") as file:
|
async with sftp.open("/etc/bosminer.toml") as file:
|
||||||
toml_data = toml.loads(await file.read())
|
toml_data = toml.loads(await file.read())
|
||||||
logging.debug(f"{self}: Converting config file.")
|
logging.debug(f"{self}: Converting config file.")
|
||||||
cfg = bos_config_convert(toml_data)
|
cfg = MinerConfig().from_raw(toml_data)
|
||||||
self.config = cfg
|
self.config = cfg
|
||||||
|
return self.config
|
||||||
|
|
||||||
async def get_hostname(self) -> str:
|
async def get_hostname(self) -> str:
|
||||||
"""Get miner hostname.
|
"""Get miner hostname.
|
||||||
@@ -192,11 +193,17 @@ class BOSMiner(BaseMiner):
|
|||||||
logging.debug(f"{self}: Sending config.")
|
logging.debug(f"{self}: Sending config.")
|
||||||
if ip_user:
|
if ip_user:
|
||||||
suffix = str(self.ip).split(".")[-1]
|
suffix = str(self.ip).split(".")[-1]
|
||||||
toml_conf = toml.dumps(
|
toml_conf = (
|
||||||
general_config_convert_bos(yaml_config, user_suffix=suffix)
|
MinerConfig()
|
||||||
|
.from_yaml(yaml_config)
|
||||||
|
.as_bos(model=self.model.replace(" (BOS)", ""), user_suffix=suffix)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
toml_conf = toml.dumps(general_config_convert_bos(yaml_config))
|
toml_conf = (
|
||||||
|
MinerConfig()
|
||||||
|
.from_yaml(yaml_config)
|
||||||
|
.as_bos(model=self.model.replace(" (BOS)", ""))
|
||||||
|
)
|
||||||
async with (await self._get_ssh_connection()) as conn:
|
async with (await self._get_ssh_connection()) as conn:
|
||||||
logging.debug(f"{self}: Opening SFTP connection.")
|
logging.debug(f"{self}: Opening SFTP connection.")
|
||||||
async with conn.start_sftp_client() as sftp:
|
async with conn.start_sftp_client() as sftp:
|
||||||
@@ -393,4 +400,4 @@ class BOSMiner(BaseMiner):
|
|||||||
|
|
||||||
async def get_mac(self):
|
async def get_mac(self):
|
||||||
result = await self.send_ssh_command("cat /sys/class/net/eth0/address")
|
result = await self.send_ssh_command("cat /sys/class/net/eth0/address")
|
||||||
return result.upper()
|
return result.upper().strip()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import asyncssh
|
import ipaddress
|
||||||
|
|
||||||
from API.bosminer import BOSMinerAPI
|
from API.bosminer import BOSMinerAPI
|
||||||
from miners import BaseMiner
|
from miners import BaseMiner
|
||||||
@@ -9,6 +9,7 @@ from miners import BaseMiner
|
|||||||
class BOSMinerOld(BaseMiner):
|
class BOSMinerOld(BaseMiner):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
|
self.ip = ipaddress.ip_address(ip)
|
||||||
self.api = BOSMinerAPI(ip)
|
self.api = BOSMinerAPI(ip)
|
||||||
self.api_type = "BOSMiner"
|
self.api_type = "BOSMiner"
|
||||||
self.uname = "root"
|
self.uname = "root"
|
||||||
@@ -22,14 +23,17 @@ class BOSMinerOld(BaseMiner):
|
|||||||
result = None
|
result = None
|
||||||
|
|
||||||
# open an ssh connection
|
# open an ssh connection
|
||||||
async with await asyncssh.connect("192.168.1.11", username="root") as conn:
|
async with (await self._get_ssh_connection()) as conn:
|
||||||
# 3 retries
|
# 3 retries
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
try:
|
try:
|
||||||
# run the command and get the result
|
# run the command and get the result
|
||||||
result = await conn.run(cmd)
|
result = await conn.run(cmd)
|
||||||
result = result.stdout
|
if result.stdout:
|
||||||
|
result = result.stdout
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
if e == "SSH connection closed":
|
||||||
|
return "Update completed."
|
||||||
# if the command fails, log it
|
# if the command fails, log it
|
||||||
logging.warning(f"{self} command {cmd} error: {e}")
|
logging.warning(f"{self} command {cmd} error: {e}")
|
||||||
|
|
||||||
@@ -40,6 +44,7 @@ class BOSMinerOld(BaseMiner):
|
|||||||
# return the result, either command output or None
|
# return the result, either command output or None
|
||||||
return str(result)
|
return str(result)
|
||||||
|
|
||||||
|
|
||||||
async def update_to_plus(self):
|
async def update_to_plus(self):
|
||||||
result = await self.send_ssh_command("opkg update && opkg install bos_plus")
|
result = await self.send_ssh_command("opkg update && opkg install bos_plus")
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class BTMiner(BaseMiner):
|
|||||||
logging.warning(f"Failed to get model for miner: {self}")
|
logging.warning(f"Failed to get model for miner: {self}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_hostname(self) -> str:
|
async def get_hostname(self) -> str or None:
|
||||||
if self.hostname:
|
if self.hostname:
|
||||||
return self.hostname
|
return self.hostname
|
||||||
try:
|
try:
|
||||||
@@ -42,10 +42,10 @@ class BTMiner(BaseMiner):
|
|||||||
return self.hostname
|
return self.hostname
|
||||||
except APIError:
|
except APIError:
|
||||||
logging.info(f"Failed to get hostname for miner: {self}")
|
logging.info(f"Failed to get hostname for miner: {self}")
|
||||||
return "?"
|
return None
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.warning(f"Failed to get hostname for miner: {self}")
|
logging.warning(f"Failed to get hostname for miner: {self}")
|
||||||
return "?"
|
return None
|
||||||
|
|
||||||
async def get_board_info(self) -> dict:
|
async def get_board_info(self) -> dict:
|
||||||
"""Gets data on each board and chain in the miner."""
|
"""Gets data on each board and chain in the miner."""
|
||||||
@@ -147,6 +147,9 @@ class BTMiner(BaseMiner):
|
|||||||
if summary_data[0].get("MAC"):
|
if summary_data[0].get("MAC"):
|
||||||
mac = summary_data[0]["MAC"]
|
mac = summary_data[0]["MAC"]
|
||||||
|
|
||||||
|
if summary_data[0].get("Env Temp"):
|
||||||
|
data.env_temp = summary_data[0]["Env Temp"]
|
||||||
|
|
||||||
data.fan_1 = summary_data[0]["Fan Speed In"]
|
data.fan_1 = summary_data[0]["Fan Speed In"]
|
||||||
data.fan_2 = summary_data[0]["Fan Speed Out"]
|
data.fan_2 = summary_data[0]["Fan Speed Out"]
|
||||||
|
|
||||||
@@ -237,7 +240,7 @@ class BTMiner(BaseMiner):
|
|||||||
logging.info(f"Failed to get mac: {self}")
|
logging.info(f"Failed to get mac: {self}")
|
||||||
mac = None
|
mac = None
|
||||||
|
|
||||||
if mac:
|
if mac:
|
||||||
data.mac = mac
|
data.mac = mac
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class CGMiner(BaseMiner):
|
|||||||
return self.model
|
return self.model
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_hostname(self) -> str:
|
async def get_hostname(self) -> str or None:
|
||||||
if self.hostname:
|
if self.hostname:
|
||||||
return self.hostname
|
return self.hostname
|
||||||
try:
|
try:
|
||||||
@@ -44,9 +44,9 @@ class CGMiner(BaseMiner):
|
|||||||
self.hostname = host
|
self.hostname = host
|
||||||
return self.hostname
|
return self.hostname
|
||||||
else:
|
else:
|
||||||
return "?"
|
return None
|
||||||
except Exception:
|
except Exception:
|
||||||
return "?"
|
return None
|
||||||
|
|
||||||
async def send_ssh_command(self, cmd):
|
async def send_ssh_command(self, cmd):
|
||||||
result = None
|
result = None
|
||||||
|
|||||||
10
miners/_types/avalonminer/A10X/A1026.py
Normal file
10
miners/_types/avalonminer/A10X/A1026.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class Avalon1026(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "Avalon 1026"
|
||||||
|
self.nominal_chips = 80
|
||||||
|
self.fan_count = 2
|
||||||
@@ -6,5 +6,5 @@ class Avalon1047(BaseMiner):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "Avalon 1047"
|
self.model = "Avalon 1047"
|
||||||
self.nominal_chips = 114
|
self.nominal_chips = 80
|
||||||
self.fan_count = 4
|
self.fan_count = 2
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
|
from .A1026 import Avalon1026
|
||||||
from .A1047 import Avalon1047
|
from .A1047 import Avalon1047
|
||||||
from .A1066 import Avalon1066
|
from .A1066 import Avalon1066
|
||||||
|
|||||||
10
miners/_types/avalonminer/A7X/A721.py
Normal file
10
miners/_types/avalonminer/A7X/A721.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class Avalon721(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "Avalon 721"
|
||||||
|
self.chip_count = 18 # This miner has 4 boards totaling 72
|
||||||
|
self.fan_count = 1 # also only 1 fan
|
||||||
10
miners/_types/avalonminer/A7X/A741.py
Normal file
10
miners/_types/avalonminer/A7X/A741.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class Avalon741(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "Avalon 741"
|
||||||
|
self.chip_count = 22 # This miner has 4 boards totaling 88
|
||||||
|
self.fan_count = 1 # also only 1 fan
|
||||||
10
miners/_types/avalonminer/A7X/A761.py
Normal file
10
miners/_types/avalonminer/A7X/A761.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class Avalon761(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "Avalon 761"
|
||||||
|
self.chip_count = 18 # This miner has 4 boards totaling 72
|
||||||
|
self.fan_count = 1 # also only 1 fan
|
||||||
3
miners/_types/avalonminer/A7X/__init__.py
Normal file
3
miners/_types/avalonminer/A7X/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .A721 import Avalon721
|
||||||
|
from .A741 import Avalon741
|
||||||
|
from .A761 import Avalon761
|
||||||
@@ -6,4 +6,5 @@ class Avalon821(BaseMiner):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "Avalon 821"
|
self.model = "Avalon 821"
|
||||||
self.fan_count = 2
|
self.chip_count = 26 # This miner has 4 boards totaling 104
|
||||||
|
self.fan_count = 1 # also only 1 fan
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ class Avalon841(BaseMiner):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "Avalon 841"
|
self.model = "Avalon 841"
|
||||||
self.fan_count = 2
|
self.chip_count = 26 # This miner has 4 boards totaling 104
|
||||||
|
self.fan_count = 1 # also only 1 fan
|
||||||
|
|||||||
10
miners/_types/avalonminer/A8X/A851.py
Normal file
10
miners/_types/avalonminer/A8X/A851.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class Avalon851(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "Avalon 851"
|
||||||
|
self.chip_count = 26 # This miner has 4 boards totaling 104
|
||||||
|
self.fan_count = 1 # also only 1 fan
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
from .A821 import Avalon821
|
from .A821 import Avalon821
|
||||||
from .A841 import Avalon841
|
from .A841 import Avalon841
|
||||||
|
from .A851 import Avalon851
|
||||||
|
|||||||
10
miners/_types/avalonminer/A9X/A921.py
Normal file
10
miners/_types/avalonminer/A9X/A921.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class Avalon921(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "Avalon 921"
|
||||||
|
self.chip_count = 26 # This miner has 4 boards totaling 104
|
||||||
|
self.fan_count = 1 # also only 1 fan
|
||||||
1
miners/_types/avalonminer/A9X/__init__.py
Normal file
1
miners/_types/avalonminer/A9X/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .A921 import Avalon921
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
|
from .A7X import *
|
||||||
from .A8X import *
|
from .A8X import *
|
||||||
|
from .A9X import *
|
||||||
from .A10X import *
|
from .A10X import *
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
from miners import BaseMiner
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class M21S(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "M21S"
|
||||||
|
self.nominal_chips = 66
|
||||||
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
class M21SV60(BaseMiner):
|
class M21SV60(BaseMiner):
|
||||||
def __init__(self, ip: str):
|
def __init__(self, ip: str):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ from .M20S import M20S
|
|||||||
from .M20S_Plus import M20SPlus
|
from .M20S_Plus import M20SPlus
|
||||||
|
|
||||||
from .M21 import M21
|
from .M21 import M21
|
||||||
from .M21S import M21SV20, M21SV60
|
from .M21S import M21S, M21SV20, M21SV60
|
||||||
from .M21S_Plus import M21SPlus
|
from .M21S_Plus import M21SPlus
|
||||||
|
|||||||
@@ -17,3 +17,30 @@ class M30SV50(BaseMiner):
|
|||||||
self.model = "M30S V50"
|
self.model = "M30S V50"
|
||||||
self.nominal_chips = 156
|
self.nominal_chips = 156
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
class M30SVG20(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "M30S VG20"
|
||||||
|
self.nominal_chips = 70
|
||||||
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
class M30SVE20(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "M30S VE20"
|
||||||
|
self.nominal_chips = 111
|
||||||
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
class M30SVE10(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "M30S VE10"
|
||||||
|
self.nominal_chips = 105
|
||||||
|
self.fan_count = 2
|
||||||
|
|||||||
@@ -10,6 +10,15 @@ class M30SPlus(BaseMiner):
|
|||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
class M30SPlusVG60(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "M30S+ VG60"
|
||||||
|
self.nominal_chips = 86
|
||||||
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
class M30SPlusVE40(BaseMiner):
|
class M30SPlusVE40(BaseMiner):
|
||||||
def __init__(self, ip: str):
|
def __init__(self, ip: str):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -17,3 +26,12 @@ class M30SPlusVE40(BaseMiner):
|
|||||||
self.model = "M30S+ VE40"
|
self.model = "M30S+ VE40"
|
||||||
self.nominal_chips = 156
|
self.nominal_chips = 156
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
class M30SPlusVF20(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "M30S+ VF20"
|
||||||
|
self.nominal_chips = 111
|
||||||
|
self.fan_count = 2
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
from miners import BaseMiner
|
from miners import BaseMiner
|
||||||
|
|
||||||
|
|
||||||
|
class M30SPlusPlus(BaseMiner):
|
||||||
|
def __init__(self, ip: str):
|
||||||
|
super().__init__()
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "M30S++"
|
||||||
|
self.nominal_chips = 111
|
||||||
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
class M30SPlusPlusVG30(BaseMiner):
|
class M30SPlusPlusVG30(BaseMiner):
|
||||||
def __init__(self, ip: str):
|
def __init__(self, ip: str):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from .M30S import M30S, M30SV50
|
from .M30S import M30S, M30SVE10, M30SVE20, M30SVG20, M30SV50
|
||||||
from .M30S_Plus import M30SPlus, M30SPlusVE40
|
from .M30S_Plus import M30SPlus, M30SPlusVG60, M30SPlusVE40, M30SPlusVF20
|
||||||
from .M30S_Plus_Plus import M30SPlusPlusVG30, M30SPlusPlusVG40
|
from .M30S_Plus_Plus import M30SPlusPlus, M30SPlusPlusVG30, M30SPlusPlusVG40
|
||||||
|
|
||||||
from .M31S import M31S
|
from .M31S import M31S
|
||||||
from .M31S_Plus import M31SPlus, M31SPlusVE20
|
from .M31S_Plus import M31SPlus, M31SPlusVE20
|
||||||
|
|||||||
@@ -1,87 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X17 import BMMinerX17
|
||||||
from miners._types import S17 # noqa - Ignore access to _module
|
from miners._types import S17 # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
class BMMinerS17(BMMinerX17, S17):
|
||||||
# TODO add config
|
|
||||||
|
|
||||||
|
|
||||||
class BMMinerS17(BMMiner, S17):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
|
||||||
except httpx.ReadTimeout:
|
|
||||||
# Expected behaviour
|
|
||||||
pass
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if not data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_light(self):
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,84 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X17 import BMMinerX17
|
||||||
from miners._types import S17Plus # noqa - Ignore access to _module
|
from miners._types import S17Plus # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
class BMMinerS17Plus(BMMinerX17, S17Plus):
|
||||||
class BMMinerS17Plus(BMMiner, S17Plus):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
|
||||||
except httpx.ReadTimeout:
|
|
||||||
# Expected behaviour
|
|
||||||
pass
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if not data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_light(self):
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,84 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X17 import BMMinerX17
|
||||||
from miners._types import S17Pro # noqa - Ignore access to _module
|
from miners._types import S17Pro # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
class BMMinerS17Pro(BMMinerX17, S17Pro):
|
||||||
class BMMinerS17Pro(BMMiner, S17Pro):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
|
||||||
except httpx.ReadTimeout:
|
|
||||||
# Expected behaviour
|
|
||||||
pass
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if not data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_light(self):
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,84 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X17 import BMMinerX17
|
||||||
from miners._types import S17e # noqa - Ignore access to _module
|
from miners._types import S17e # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
class BMMinerS17e(BMMinerX17, S17e):
|
||||||
class BMMinerS17e(BMMiner, S17e):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
|
||||||
except httpx.ReadTimeout:
|
|
||||||
# Expected behaviour
|
|
||||||
pass
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if not data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_light(self):
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,84 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X17 import BMMinerX17
|
||||||
from miners._types import T17 # noqa - Ignore access to _module
|
from miners._types import T17 # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
class BMMinerT17(BMMinerX17, T17):
|
||||||
class BMMinerT17(BMMiner, T17):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
|
||||||
except httpx.ReadTimeout:
|
|
||||||
# Expected behaviour
|
|
||||||
pass
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if not data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_light(self):
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,84 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X17 import BMMinerX17
|
||||||
from miners._types import T17Plus # noqa - Ignore access to _module
|
from miners._types import T17Plus # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
class BMMinerT17Plus(BMMinerX17, T17Plus):
|
||||||
class BMMinerT17Plus(BMMiner, T17Plus):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
|
||||||
except httpx.ReadTimeout:
|
|
||||||
# Expected behaviour
|
|
||||||
pass
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if not data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_light(self):
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,84 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X17 import BMMinerX17
|
||||||
from miners._types import T17e # noqa - Ignore access to _module
|
from miners._types import T17e # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
class BMMinerT17e(BMMinerX17, T17e):
|
||||||
class BMMinerT17e(BMMiner, T17e):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
|
||||||
except httpx.ReadTimeout:
|
|
||||||
# Expected behaviour
|
|
||||||
pass
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if not data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_light(self):
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data["isBlinking"]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
83
miners/antminer/bmminer/X17/X17.py
Normal file
83
miners/antminer/bmminer/X17/X17.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
from miners._backends import BMMiner # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
|
||||||
|
class BMMinerX17(BMMiner):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def get_hostname(self) -> str or None:
|
||||||
|
hostname = None
|
||||||
|
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.get(url, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if len(data.keys()) > 0:
|
||||||
|
if "hostname" in data.keys():
|
||||||
|
hostname = data["hostname"]
|
||||||
|
return hostname
|
||||||
|
|
||||||
|
async def get_mac(self):
|
||||||
|
mac = None
|
||||||
|
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.get(url, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if len(data.keys()) > 0:
|
||||||
|
if "macaddr" in data.keys():
|
||||||
|
mac = data["macaddr"]
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
try:
|
||||||
|
await client.post(url, data={"action": "startBlink"}, auth=auth)
|
||||||
|
except httpx.ReadTimeout:
|
||||||
|
# Expected behaviour
|
||||||
|
pass
|
||||||
|
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if data["isBlinking"]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
await client.post(url, data={"action": "stopBlink"}, auth=auth)
|
||||||
|
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if not data["isBlinking"]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def check_light(self):
|
||||||
|
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.post(url, data={"action": "onPageLoaded"}, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if data["isBlinking"]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.get(url, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -1,73 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X19 import BMMinerX19
|
||||||
from miners._types import S19 # noqa - Ignore access to _module
|
from miners._types import S19 # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
class BMMinerS19(BMMinerX19, S19):
|
||||||
# TODO add config
|
|
||||||
|
|
||||||
|
|
||||||
class BMMinerS19(BMMiner, S19):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "true"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B000":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "false"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B100":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,70 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X19 import BMMinerX19
|
||||||
from miners._types import S19Pro # noqa - Ignore access to _module
|
from miners._types import S19Pro # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
class BMMinerS19Pro(BMMinerX19, S19Pro):
|
||||||
class BMMinerS19Pro(BMMiner, S19Pro):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "true"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B000":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "false"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B100":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,70 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X19 import BMMinerX19
|
||||||
from miners._types import S19a # noqa - Ignore access to _module
|
from miners._types import S19a # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
class BMMinerS19a(BMMinerX19, S19a):
|
||||||
class BMMinerS19a(BMMiner, S19a):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "true"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B000":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "false"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B100":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,70 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X19 import BMMinerX19
|
||||||
from miners._types import S19j # noqa - Ignore access to _module
|
from miners._types import S19j # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
class BMMinerS19j(BMMinerX19, S19j):
|
||||||
class BMMinerS19j(BMMiner, S19j):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "true"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B000":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "false"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B100":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,70 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X19 import BMMinerX19
|
||||||
from miners._types import S19jPro # noqa - Ignore access to _module
|
from miners._types import S19jPro # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
class BMMinerS19jPro(BMMinerX19, S19jPro):
|
||||||
class BMMinerS19jPro(BMMiner, S19jPro):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "true"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B000":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "false"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B100":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -1,70 +1,8 @@
|
|||||||
from miners._backends import BMMiner # noqa - Ignore access to _module
|
from .X19 import BMMinerX19
|
||||||
from miners._types import T19 # noqa - Ignore access to _module
|
from miners._types import T19 # noqa - Ignore access to _module
|
||||||
|
|
||||||
import httpx
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
class BMMinerT19(BMMinerX19, T19):
|
||||||
class BMMinerT19(BMMiner, T19):
|
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
async def get_hostname(self) -> str or None:
|
|
||||||
hostname = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "hostname" in data.keys():
|
|
||||||
hostname = data["hostname"]
|
|
||||||
return hostname
|
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
mac = None
|
|
||||||
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if len(data.keys()) > 0:
|
|
||||||
if "macaddr" in data.keys():
|
|
||||||
mac = data["macaddr"]
|
|
||||||
return mac
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "true"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B000":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
data = json.dumps({"blink": "false"})
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.post(url, data=data, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
data = data.json()
|
|
||||||
if data.get("code") == "B100":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
|
||||||
auth = httpx.DigestAuth("root", "root")
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
if data.status_code == 200:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
102
miners/antminer/bmminer/X19/X19.py
Normal file
102
miners/antminer/bmminer/X19/X19.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
from miners._backends import BMMiner # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from config import MinerConfig
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
import json
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
|
class BMMinerX19(BMMiner):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def get_config(self) -> MinerConfig:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/get_miner_conf.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.get(url, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
self.config = MinerConfig().from_raw(data)
|
||||||
|
return self.config
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/set_miner_conf.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_x19(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_x19()
|
||||||
|
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
await client.post(url, data=conf, auth=auth)
|
||||||
|
except httpx.ReadTimeout:
|
||||||
|
pass
|
||||||
|
for i in range(7):
|
||||||
|
data = await self.get_config()
|
||||||
|
if data.as_x19() == conf:
|
||||||
|
break
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
async def get_hostname(self) -> str or None:
|
||||||
|
hostname = None
|
||||||
|
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.get(url, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if len(data.keys()) > 0:
|
||||||
|
if "hostname" in data.keys():
|
||||||
|
hostname = data["hostname"]
|
||||||
|
return hostname
|
||||||
|
|
||||||
|
async def get_mac(self):
|
||||||
|
mac = None
|
||||||
|
url = f"http://{self.ip}/cgi-bin/get_system_info.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.get(url, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if len(data.keys()) > 0:
|
||||||
|
if "macaddr" in data.keys():
|
||||||
|
mac = data["macaddr"]
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
data = json.dumps({"blink": "true"})
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.post(url, data=data, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if data.get("code") == "B000":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/blink.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
data = json.dumps({"blink": "false"})
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.post(url, data=data, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
data = data.json()
|
||||||
|
if data.get("code") == "B100":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
url = f"http://{self.ip}/cgi-bin/reboot.cgi"
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
data = await client.get(url, auth=auth)
|
||||||
|
if data.status_code == 200:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
238
miners/avalonminer/cgminer/A10X/A1026.py
Normal file
238
miners/avalonminer/cgminer/A10X/A1026.py
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
|
from miners._types import Avalon1026 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CGMinerAvalon1026(CGMiner, Avalon1026):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
@@ -1,8 +1,238 @@
|
|||||||
from miners._backends import CGMiner # noqa - Ignore access to _module
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
from miners._types import Avalon1047 # noqa - Ignore access to _module
|
from miners._types import Avalon1047 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon1047(CGMiner, Avalon1047):
|
class CGMinerAvalon1047(CGMiner, Avalon1047):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
|
|||||||
@@ -1,8 +1,238 @@
|
|||||||
from miners._backends import CGMiner # noqa - Ignore access to _module
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
from miners._types import Avalon1066 # noqa - Ignore access to _module
|
from miners._types import Avalon1066 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon1066(CGMiner, Avalon1066):
|
class CGMinerAvalon1066(CGMiner, Avalon1066):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
|
from .A1026 import CGMinerAvalon1026
|
||||||
from .A1047 import CGMinerAvalon1047
|
from .A1047 import CGMinerAvalon1047
|
||||||
from .A1066 import CGMinerAvalon1066
|
from .A1066 import CGMinerAvalon1066
|
||||||
|
|||||||
238
miners/avalonminer/cgminer/A7X/A721.py
Normal file
238
miners/avalonminer/cgminer/A7X/A721.py
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
|
from miners._types import Avalon721 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CGMinerAvalon721(CGMiner, Avalon721):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
238
miners/avalonminer/cgminer/A7X/A741.py
Normal file
238
miners/avalonminer/cgminer/A7X/A741.py
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
|
from miners._types import Avalon741 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CGMinerAvalon741(CGMiner, Avalon741):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
238
miners/avalonminer/cgminer/A7X/A761.py
Normal file
238
miners/avalonminer/cgminer/A7X/A761.py
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
|
from miners._types import Avalon761 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CGMinerAvalon761(CGMiner, Avalon761):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
3
miners/avalonminer/cgminer/A7X/__init__.py
Normal file
3
miners/avalonminer/cgminer/A7X/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .A721 import CGMinerAvalon721
|
||||||
|
from .A741 import CGMinerAvalon741
|
||||||
|
from .A761 import CGMinerAvalon761
|
||||||
@@ -1,8 +1,238 @@
|
|||||||
from miners._backends import CGMiner # noqa - Ignore access to _module
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
from miners._types import Avalon821 # noqa - Ignore access to _module
|
from miners._types import Avalon821 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon821(CGMiner, Avalon821):
|
class CGMinerAvalon821(CGMiner, Avalon821):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
|
|||||||
@@ -1,8 +1,238 @@
|
|||||||
from miners._backends import CGMiner # noqa - Ignore access to _module
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
from miners._types import Avalon841 # noqa - Ignore access to _module
|
from miners._types import Avalon841 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon841(CGMiner, Avalon841):
|
class CGMinerAvalon841(CGMiner, Avalon841):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname:
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
|
|||||||
238
miners/avalonminer/cgminer/A8X/A851.py
Normal file
238
miners/avalonminer/cgminer/A8X/A851.py
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
|
from miners._types import Avalon851 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CGMinerAvalon851(CGMiner, Avalon851):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
from .A821 import CGMinerAvalon821
|
from .A821 import CGMinerAvalon821
|
||||||
from .A841 import CGMinerAvalon841
|
from .A841 import CGMinerAvalon841
|
||||||
|
from .A851 import CGMinerAvalon851
|
||||||
|
|||||||
238
miners/avalonminer/cgminer/A9X/A921.py
Normal file
238
miners/avalonminer/cgminer/A9X/A921.py
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
from miners._backends import CGMiner # noqa - Ignore access to _module
|
||||||
|
from miners._types import Avalon921 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
from data import MinerData
|
||||||
|
from settings import MINER_FACTORY_GET_VERSION_RETRIES as DATA_RETRIES
|
||||||
|
import re
|
||||||
|
from config import MinerConfig
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CGMinerAvalon921(CGMiner, Avalon921):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
async def fault_light_on(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-1")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
data = await self.api.ascset(0, "led", "1-0")
|
||||||
|
if data["STATUS"][0]["Msg"] == "ASC 0 set OK":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def reboot(self) -> bool:
|
||||||
|
if (await self.api.restart())["STATUS"] == "RESTART":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_config(self, yaml_config, ip_user: bool = False) -> None:
|
||||||
|
"""Configures miner with yaml config."""
|
||||||
|
raise NotImplementedError
|
||||||
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
if ip_user:
|
||||||
|
suffix = str(self.ip).split(".")[-1]
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon(user_suffix=suffix)
|
||||||
|
else:
|
||||||
|
conf = MinerConfig().from_yaml(yaml_config).as_avalon()
|
||||||
|
data = await self.api.ascset(
|
||||||
|
0, "setpool", f"root,root,{conf}"
|
||||||
|
) # this should work but doesn't
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def get_mac(self) -> str:
|
||||||
|
mac = None
|
||||||
|
version = await self.api.version()
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version.keys():
|
||||||
|
if "MAC" in version["VERSION"][0].keys():
|
||||||
|
base_mac = version["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
async def get_data(self):
|
||||||
|
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
|
||||||
|
|
||||||
|
model = await self.get_model()
|
||||||
|
mac = None
|
||||||
|
|
||||||
|
if model:
|
||||||
|
data.model = model
|
||||||
|
|
||||||
|
miner_data = None
|
||||||
|
for i in range(DATA_RETRIES):
|
||||||
|
miner_data = await self.api.multicommand(
|
||||||
|
"version", "summary", "pools", "stats"
|
||||||
|
)
|
||||||
|
if miner_data:
|
||||||
|
break
|
||||||
|
if not miner_data:
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
mac = await self.get_mac()
|
||||||
|
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
return data
|
||||||
|
|
||||||
|
summary = miner_data.get("summary")
|
||||||
|
version = miner_data.get("version")
|
||||||
|
pools = miner_data.get("pools")
|
||||||
|
stats = miner_data.get("stats")
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
hr = summary[0].get("SUMMARY")
|
||||||
|
if hr:
|
||||||
|
if len(hr) > 0:
|
||||||
|
hr = hr[0].get("MHS 1m")
|
||||||
|
if hr:
|
||||||
|
data.hashrate = round(hr / 1000000, 2)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
if "VERSION" in version[0].keys():
|
||||||
|
if "MAC" in version[0]["VERSION"][0].keys():
|
||||||
|
base_mac = version[0]["VERSION"][0]["MAC"].upper()
|
||||||
|
# parse the MAC into a recognizable form
|
||||||
|
mac = ":".join(
|
||||||
|
[base_mac[i : (i + 2)] for i in range(0, len(base_mac), 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
stats_data = stats[0].get("STATS")
|
||||||
|
if stats_data:
|
||||||
|
for key in stats_data[0].keys():
|
||||||
|
if key.startswith("MM ID"):
|
||||||
|
raw_data = self.parse_stats(stats_data[0][key])
|
||||||
|
for fan in range(self.fan_count):
|
||||||
|
if f"Fan{fan+1}" in raw_data:
|
||||||
|
setattr(
|
||||||
|
data,
|
||||||
|
f"fan_{fan+1}",
|
||||||
|
int(raw_data[f"Fan{fan+1}"]),
|
||||||
|
)
|
||||||
|
if "MTmax" in raw_data.keys():
|
||||||
|
data.left_board_chip_temp = int(raw_data["MTmax"][0])
|
||||||
|
data.center_board_chip_temp = int(raw_data["MTmax"][1])
|
||||||
|
data.right_board_chip_temp = int(raw_data["MTmax"][2])
|
||||||
|
if "MTavg" in raw_data.keys():
|
||||||
|
data.left_board_temp = int(raw_data["MTavg"][0])
|
||||||
|
data.center_board_temp = int(raw_data["MTavg"][1])
|
||||||
|
data.right_board_temp = int(raw_data["MTavg"][2])
|
||||||
|
|
||||||
|
if "PVT_T0" in raw_data:
|
||||||
|
data.left_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T0"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T1" in raw_data:
|
||||||
|
data.center_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T1"] if not item == "0"]
|
||||||
|
)
|
||||||
|
if "PVT_T2" in raw_data:
|
||||||
|
data.right_chips = len(
|
||||||
|
[item for item in raw_data["PVT_T2"] if not item == "0"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if pools:
|
||||||
|
pool_1 = None
|
||||||
|
pool_2 = None
|
||||||
|
pool_1_user = None
|
||||||
|
pool_2_user = None
|
||||||
|
pool_1_quota = 1
|
||||||
|
pool_2_quota = 1
|
||||||
|
quota = 0
|
||||||
|
for pool in pools[0].get("POOLS"):
|
||||||
|
if not pool_1_user:
|
||||||
|
pool_1_user = pool.get("User")
|
||||||
|
pool_1 = pool["URL"]
|
||||||
|
pool_1_quota = pool["Quota"]
|
||||||
|
elif not pool_2_user:
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if not pool.get("User") == pool_1_user:
|
||||||
|
if not pool_2_user == pool.get("User"):
|
||||||
|
pool_2_user = pool.get("User")
|
||||||
|
pool_2 = pool["URL"]
|
||||||
|
pool_2_quota = pool["Quota"]
|
||||||
|
if pool_2_user and not pool_2_user == pool_1_user:
|
||||||
|
quota = f"{pool_1_quota}/{pool_2_quota}"
|
||||||
|
|
||||||
|
if pool_1:
|
||||||
|
pool_1 = pool_1.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_1_url = pool_1
|
||||||
|
|
||||||
|
if pool_1_user:
|
||||||
|
data.pool_1_user = pool_1_user
|
||||||
|
|
||||||
|
if pool_2:
|
||||||
|
pool_2 = pool_2.replace("stratum+tcp://", "").replace(
|
||||||
|
"stratum2+tcp://", ""
|
||||||
|
)
|
||||||
|
data.pool_2_url = pool_2
|
||||||
|
|
||||||
|
if pool_2_user:
|
||||||
|
data.pool_2_user = pool_2_user
|
||||||
|
|
||||||
|
if quota:
|
||||||
|
data.pool_split = str(quota)
|
||||||
|
|
||||||
|
hostname = await self.get_hostname()
|
||||||
|
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
else:
|
||||||
|
mac = await self.get_mac()
|
||||||
|
if mac:
|
||||||
|
data.mac = mac
|
||||||
|
if hostname and not hostname == "?":
|
||||||
|
data.hostname = hostname
|
||||||
|
elif mac:
|
||||||
|
data.hostname = f"Avalon{mac.replace(':', '')[-6:]}"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_stats(stats):
|
||||||
|
_stats_items = re.findall(".+?\[*?]", stats)
|
||||||
|
stats_items = []
|
||||||
|
stats_dict = {}
|
||||||
|
for item in _stats_items:
|
||||||
|
if ":" in item:
|
||||||
|
data = item.replace("]", "").split("[")
|
||||||
|
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||||
|
data_dict = {}
|
||||||
|
for key, val in [tuple(item) for item in data_list]:
|
||||||
|
data_dict[key] = val
|
||||||
|
raw_data = [data[0].strip(), data_dict]
|
||||||
|
else:
|
||||||
|
raw_data = [
|
||||||
|
value
|
||||||
|
for value in item.replace("[", " ")
|
||||||
|
.replace("]", " ")
|
||||||
|
.split(" ")[:-1]
|
||||||
|
if value != ""
|
||||||
|
]
|
||||||
|
if len(raw_data) == 1:
|
||||||
|
raw_data.append("")
|
||||||
|
if raw_data[0] == "":
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
|
||||||
|
if len(raw_data) == 2:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1]
|
||||||
|
else:
|
||||||
|
stats_dict[raw_data[0]] = raw_data[1:]
|
||||||
|
stats_items.append(raw_data)
|
||||||
|
|
||||||
|
return stats_dict
|
||||||
1
miners/avalonminer/cgminer/A9X/__init__.py
Normal file
1
miners/avalonminer/cgminer/A9X/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .A921 import CGMinerAvalon921
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
|
from .A7X import *
|
||||||
from .A8X import *
|
from .A8X import *
|
||||||
|
from .A9X import *
|
||||||
from .A10X import *
|
from .A10X import *
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ MINER_CLASSES = {
|
|||||||
"BTMiner": BTMinerM21,
|
"BTMiner": BTMinerM21,
|
||||||
},
|
},
|
||||||
"M21S": {
|
"M21S": {
|
||||||
"Default": BTMinerM21SV60,
|
"Default": BTMinerM21S,
|
||||||
"BTMiner": BTMinerM21SV60,
|
"BTMiner": BTMinerM21S,
|
||||||
"60": BTMinerM21SV60,
|
"60": BTMinerM21SV60,
|
||||||
"20": BTMinerM21SV20,
|
"20": BTMinerM21SV20,
|
||||||
},
|
},
|
||||||
@@ -146,17 +146,22 @@ MINER_CLASSES = {
|
|||||||
"Default": BTMinerM30S,
|
"Default": BTMinerM30S,
|
||||||
"BTMiner": BTMinerM30S,
|
"BTMiner": BTMinerM30S,
|
||||||
"50": BTMinerM30SV50,
|
"50": BTMinerM30SV50,
|
||||||
|
"G20": BTMinerM30SVG20,
|
||||||
|
"E20": BTMinerM30SVE20,
|
||||||
|
"E10": BTMinerM30SVE10,
|
||||||
},
|
},
|
||||||
"M30S+": {
|
"M30S+": {
|
||||||
"Default": BTMinerM30SPlus,
|
"Default": BTMinerM30SPlus,
|
||||||
"BTMiner": BTMinerM30SPlus,
|
"BTMiner": BTMinerM30SPlus,
|
||||||
"40": BTMinerM30SPlusVE40,
|
"F20": BTMinerM30SPlusVF20,
|
||||||
|
"E40": BTMinerM30SPlusVE40,
|
||||||
|
"G60": BTMinerM30SPlusVG60,
|
||||||
},
|
},
|
||||||
"M30S++": {
|
"M30S++": {
|
||||||
"Default": BTMinerM30SPlusPlusVG40,
|
"Default": BTMinerM30SPlusPlus,
|
||||||
"BTMiner": BTMinerM30SPlusPlusVG40,
|
"BTMiner": BTMinerM30SPlusPlus,
|
||||||
"40": BTMinerM30SPlusPlusVG40,
|
"G40": BTMinerM30SPlusPlusVG40,
|
||||||
"30": BTMinerM30SPlusPlusVG30,
|
"G30": BTMinerM30SPlusPlusVG30,
|
||||||
},
|
},
|
||||||
"M31S": {
|
"M31S": {
|
||||||
"Default": BTMinerM31S,
|
"Default": BTMinerM31S,
|
||||||
@@ -165,12 +170,52 @@ MINER_CLASSES = {
|
|||||||
"M31S+": {
|
"M31S+": {
|
||||||
"Default": BTMinerM31SPlus,
|
"Default": BTMinerM31SPlus,
|
||||||
"BTMiner": BTMinerM31SPlus,
|
"BTMiner": BTMinerM31SPlus,
|
||||||
"20": BTMinerM31SPlusVE20,
|
"E20": BTMinerM31SPlusVE20,
|
||||||
},
|
},
|
||||||
"M32S": {
|
"M32S": {
|
||||||
"Default": BTMinerM32S,
|
"Default": BTMinerM32S,
|
||||||
"BTMiner": BTMinerM32S,
|
"BTMiner": BTMinerM32S,
|
||||||
},
|
},
|
||||||
|
"AvalonMiner 721": {
|
||||||
|
"Default": CGMinerAvalon721,
|
||||||
|
"CGMiner": CGMinerAvalon721,
|
||||||
|
},
|
||||||
|
"AvalonMiner 741": {
|
||||||
|
"Default": CGMinerAvalon741,
|
||||||
|
"CGMiner": CGMinerAvalon741,
|
||||||
|
},
|
||||||
|
"AvalonMiner 761": {
|
||||||
|
"Default": CGMinerAvalon761,
|
||||||
|
"CGMiner": CGMinerAvalon761,
|
||||||
|
},
|
||||||
|
"AvalonMiner 821": {
|
||||||
|
"Default": CGMinerAvalon821,
|
||||||
|
"CGMiner": CGMinerAvalon821,
|
||||||
|
},
|
||||||
|
"AvalonMiner 841": {
|
||||||
|
"Default": CGMinerAvalon841,
|
||||||
|
"CGMiner": CGMinerAvalon841,
|
||||||
|
},
|
||||||
|
"AvalonMiner 851": {
|
||||||
|
"Default": CGMinerAvalon851,
|
||||||
|
"CGMiner": CGMinerAvalon851,
|
||||||
|
},
|
||||||
|
"AvalonMiner 921": {
|
||||||
|
"Default": CGMinerAvalon921,
|
||||||
|
"CGMiner": CGMinerAvalon921,
|
||||||
|
},
|
||||||
|
"AvalonMiner 1026": {
|
||||||
|
"Default": CGMinerAvalon1026,
|
||||||
|
"CGMiner": CGMinerAvalon1026,
|
||||||
|
},
|
||||||
|
"AvalonMiner 1047": {
|
||||||
|
"Default": CGMinerAvalon1047,
|
||||||
|
"CGMiner": CGMinerAvalon1047,
|
||||||
|
},
|
||||||
|
"AvalonMiner 1066": {
|
||||||
|
"Default": CGMinerAvalon1066,
|
||||||
|
"CGMiner": CGMinerAvalon1066,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -251,22 +296,21 @@ class MinerFactory(metaclass=Singleton):
|
|||||||
if not api:
|
if not api:
|
||||||
api = "Default"
|
api = "Default"
|
||||||
|
|
||||||
# Avalonminers
|
if model not in MINER_CLASSES.keys():
|
||||||
if "avalon" in model:
|
if "avalon" in model:
|
||||||
if model == "avalon10":
|
print(model)
|
||||||
miner = CGMinerAvalon1066(str(ip))
|
if model == "avalon10":
|
||||||
else:
|
miner = CGMinerAvalon1066(str(ip))
|
||||||
miner = CGMinerAvalon821(str(ip))
|
else:
|
||||||
else:
|
miner = CGMinerAvalon821(str(ip))
|
||||||
if model not in MINER_CLASSES.keys():
|
miner = UnknownMiner(str(ip))
|
||||||
miner = UnknownMiner(str(ip))
|
return miner
|
||||||
return miner
|
if api not in MINER_CLASSES[model].keys():
|
||||||
if api not in MINER_CLASSES[model].keys():
|
api = "Default"
|
||||||
api = "Default"
|
if ver in MINER_CLASSES[model].keys():
|
||||||
if ver in MINER_CLASSES[model].keys():
|
miner = MINER_CLASSES[model][ver](str(ip))
|
||||||
miner = MINER_CLASSES[model][ver](str(ip))
|
return miner
|
||||||
return miner
|
miner = MINER_CLASSES[model][api](str(ip))
|
||||||
miner = MINER_CLASSES[model][api](str(ip))
|
|
||||||
|
|
||||||
# if we cant find a model, check if we found the API
|
# if we cant find a model, check if we found the API
|
||||||
else:
|
else:
|
||||||
@@ -402,6 +446,18 @@ class MinerFactory(metaclass=Singleton):
|
|||||||
):
|
):
|
||||||
api = "BTMiner"
|
api = "BTMiner"
|
||||||
|
|
||||||
|
# check for avalonminers
|
||||||
|
if version["VERSION"][0].get("PROD"):
|
||||||
|
_data = version["VERSION"][0]["PROD"].split("-")
|
||||||
|
model = _data[0]
|
||||||
|
if len(data) > 1:
|
||||||
|
ver = _data[1]
|
||||||
|
elif version["VERSION"][0].get("MODEL"):
|
||||||
|
_data = version["VERSION"][0]["MODEL"].split("-")
|
||||||
|
model = f"AvalonMiner {_data[0]}"
|
||||||
|
if len(data) > 1:
|
||||||
|
ver = _data[1]
|
||||||
|
|
||||||
# if we have no model from devdetails but have version, try to get it from there
|
# if we have no model from devdetails but have version, try to get it from there
|
||||||
if version and not model:
|
if version and not model:
|
||||||
# make sure version isn't blank
|
# make sure version isn't blank
|
||||||
@@ -438,10 +494,6 @@ class MinerFactory(metaclass=Singleton):
|
|||||||
_ver = model.split("V")
|
_ver = model.split("V")
|
||||||
if len(_ver) > 1:
|
if len(_ver) > 1:
|
||||||
ver = model.split("V")[1]
|
ver = model.split("V")[1]
|
||||||
if "VE" in model:
|
|
||||||
ver = model.split("VE")[1]
|
|
||||||
if "VG" in model:
|
|
||||||
ver = model.split("VG")[1]
|
|
||||||
model = model.split("V")[0]
|
model = model.split("V")[0]
|
||||||
# don't need "Bitmain", just "Antminer XX" as model
|
# don't need "Bitmain", just "Antminer XX" as model
|
||||||
if "Bitmain " in model:
|
if "Bitmain " in model:
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
from miners._backends import BTMiner # noqa - Ignore access to _module
|
from miners._backends import BTMiner # noqa - Ignore access to _module
|
||||||
from miners._types import M21SV20, M21SV60 # noqa - Ignore access to _module
|
from miners._types import M21S, M21SV20, M21SV60 # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM21S(BTMiner, M21S):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
|
||||||
class BTMinerM21SV20(BTMiner, M21SV20):
|
class BTMinerM21SV20(BTMiner, M21SV20):
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ from .M20S import BTMinerM20S
|
|||||||
from .M20S_Plus import BTMinerM20SPlus
|
from .M20S_Plus import BTMinerM20SPlus
|
||||||
|
|
||||||
from .M21 import BTMinerM21
|
from .M21 import BTMinerM21
|
||||||
from .M21S import BTMinerM21SV20, BTMinerM21SV60
|
from .M21S import BTMinerM21S, BTMinerM21SV20, BTMinerM21SV60
|
||||||
from .M21S_Plus import BTMinerM21SPlus
|
from .M21S_Plus import BTMinerM21SPlus
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
from miners._backends import BTMiner # noqa - Ignore access to _module
|
from miners._backends import BTMiner # noqa - Ignore access to _module
|
||||||
from miners._types import M30S, M30SV50 # noqa - Ignore access to _module
|
from miners._types import (
|
||||||
|
M30S,
|
||||||
|
M30SV50,
|
||||||
|
M30SVG20,
|
||||||
|
M30SVE20,
|
||||||
|
M30SVE10,
|
||||||
|
) # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
|
||||||
class BTMinerM30S(BTMiner, M30S):
|
class BTMinerM30S(BTMiner, M30S):
|
||||||
@@ -12,3 +18,21 @@ class BTMinerM30SV50(BTMiner, M30SV50):
|
|||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM30SVG20(BTMiner, M30SVG20):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM30SVE20(BTMiner, M30SVE20):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM30SVE10(BTMiner, M30SVE10):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
from miners._backends import BTMiner # noqa - Ignore access to _module
|
from miners._backends import BTMiner # noqa - Ignore access to _module
|
||||||
from miners._types import M30SPlus, M30SPlusVE40 # noqa - Ignore access to _module
|
from miners._types import (
|
||||||
|
M30SPlus,
|
||||||
|
M30SPlusVE40,
|
||||||
|
M30SPlusVF20,
|
||||||
|
M30SPlusVG60,
|
||||||
|
) # noqa - Ignore access to _module
|
||||||
|
|
||||||
|
|
||||||
class BTMinerM30SPlus(BTMiner, M30SPlus):
|
class BTMinerM30SPlus(BTMiner, M30SPlus):
|
||||||
@@ -12,3 +17,15 @@ class BTMinerM30SPlusVE40(BTMiner, M30SPlusVE40):
|
|||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM30SPlusVF20(BTMiner, M30SPlusVF20):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM30SPlusVG60(BTMiner, M30SPlusVG60):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
from miners._backends import BTMiner # noqa - Ignore access to _module
|
from miners._backends import BTMiner # noqa - Ignore access to _module
|
||||||
from miners._types import ( # noqa - Ignore access to _module
|
from miners._types import ( # noqa - Ignore access to _module
|
||||||
|
M30SPlusPlus,
|
||||||
M30SPlusPlusVG40,
|
M30SPlusPlusVG40,
|
||||||
M30SPlusPlusVG30,
|
M30SPlusPlusVG30,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM30SPlusPlus(BTMiner, M30SPlusPlus):
|
||||||
|
def __init__(self, ip: str) -> None:
|
||||||
|
super().__init__(ip)
|
||||||
|
self.ip = ip
|
||||||
|
|
||||||
|
|
||||||
class BTMinerM30SPlusPlusVG40(BTMiner, M30SPlusPlusVG40):
|
class BTMinerM30SPlusPlusVG40(BTMiner, M30SPlusPlusVG40):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
|
|||||||
@@ -1,6 +1,21 @@
|
|||||||
from .M30S import BTMinerM30S, BTMinerM30SV50
|
from .M30S import (
|
||||||
from .M30S_Plus import BTMinerM30SPlus, BTMinerM30SPlusVE40
|
BTMinerM30S,
|
||||||
from .M30S_Plus_Plus import BTMinerM30SPlusPlusVG40, BTMinerM30SPlusPlusVG30
|
BTMinerM30SVE10,
|
||||||
|
BTMinerM30SVE20,
|
||||||
|
BTMinerM30SVG20,
|
||||||
|
BTMinerM30SV50,
|
||||||
|
)
|
||||||
|
from .M30S_Plus import (
|
||||||
|
BTMinerM30SPlus,
|
||||||
|
BTMinerM30SPlusVF20,
|
||||||
|
BTMinerM30SPlusVE40,
|
||||||
|
BTMinerM30SPlusVG60,
|
||||||
|
)
|
||||||
|
from .M30S_Plus_Plus import (
|
||||||
|
BTMinerM30SPlusPlus,
|
||||||
|
BTMinerM30SPlusPlusVG40,
|
||||||
|
BTMinerM30SPlusPlusVG30,
|
||||||
|
)
|
||||||
|
|
||||||
from .M31S import BTMinerM31S
|
from .M31S import BTMinerM31S
|
||||||
from .M31S_Plus import BTMinerM31SPlus, BTMinerM31SPlusVE20
|
from .M31S_Plus import BTMinerM31SPlus, BTMinerM31SPlusVE20
|
||||||
|
|||||||
@@ -13,17 +13,19 @@ MINER_FACTORY_GET_VERSION_RETRIES: int = 3
|
|||||||
WHATSMINER_PWD = "admin"
|
WHATSMINER_PWD = "admin"
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
LOGFILE = False
|
||||||
|
|
||||||
|
settings_keys = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(
|
with open(
|
||||||
os.path.join(os.path.dirname(__file__), "settings.toml"), "r"
|
os.path.join(os.path.dirname(__file__), "settings.toml"), "r"
|
||||||
) as settings_file:
|
) as settings_file:
|
||||||
settings = toml.loads(settings_file.read())
|
settings = toml.loads(settings_file.read())
|
||||||
|
settings_keys = settings.keys()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
settings_keys = settings.keys()
|
|
||||||
|
|
||||||
if "ping_retries" in settings_keys:
|
if "ping_retries" in settings_keys:
|
||||||
NETWORK_PING_RETRIES: int = settings["ping_retries"]
|
NETWORK_PING_RETRIES: int = settings["ping_retries"]
|
||||||
if "ping_timeout" in settings_keys:
|
if "ping_timeout" in settings_keys:
|
||||||
@@ -46,3 +48,6 @@ if "whatsminer_pwd" in settings_keys:
|
|||||||
|
|
||||||
if "debug" in settings_keys:
|
if "debug" in settings_keys:
|
||||||
DEBUG: int = settings["debug"]
|
DEBUG: int = settings["debug"]
|
||||||
|
|
||||||
|
if "logfile" in settings_keys:
|
||||||
|
LOGFILE: bool = settings["logfile"]
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ reboot_threads = 300
|
|||||||
|
|
||||||
whatsminer_pwd = "admin"
|
whatsminer_pwd = "admin"
|
||||||
|
|
||||||
|
logfile = true
|
||||||
|
|
||||||
### DEBUG MODE ###
|
### DEBUG MODE ###
|
||||||
# change this to debug = true
|
# change this to debug = true
|
||||||
# to enable debug mode.
|
# to enable debug mode.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import datetime
|
|||||||
import ipaddress
|
import ipaddress
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
@@ -178,15 +179,26 @@ def create_boards_pie_chart(data):
|
|||||||
num_bad_boards = [0, 0, 0, 0]
|
num_bad_boards = [0, 0, 0, 0]
|
||||||
for item in data.keys():
|
for item in data.keys():
|
||||||
num_bad_boards[len(data[item])] += 1
|
num_bad_boards[len(data[item])] += 1
|
||||||
|
idxs = []
|
||||||
|
graph_labels = copy(labels)
|
||||||
|
graph_num_bad_board = copy(num_bad_boards)
|
||||||
|
for idx in range(len(num_bad_boards)):
|
||||||
|
if num_bad_boards[idx] == 0:
|
||||||
|
idxs.append(idx)
|
||||||
|
idxs.sort(reverse=True)
|
||||||
|
for idx in idxs:
|
||||||
|
graph_labels.pop(idx)
|
||||||
|
graph_num_bad_board.pop(idx)
|
||||||
|
|
||||||
cmap = plt.get_cmap("Blues")
|
cmap = plt.get_cmap("Blues")
|
||||||
cs = cmap(np.linspace(0.2, 0.8, num=len(num_bad_boards)))
|
cs = cmap(np.linspace(0.2, 0.8, num=len(graph_num_bad_board)))
|
||||||
|
|
||||||
# fig, ax = plt.subplots() -> causes window resizing...
|
# fig, ax = plt.subplots() -> causes window resizing...
|
||||||
fig = Figure()
|
fig = Figure()
|
||||||
ax = fig.add_subplot()
|
ax = fig.add_subplot()
|
||||||
ax.pie(
|
ax.pie(
|
||||||
num_bad_boards,
|
graph_num_bad_board,
|
||||||
labels=labels,
|
labels=graph_labels,
|
||||||
autopct="%1.2f%%",
|
autopct="%1.2f%%",
|
||||||
shadow=True,
|
shadow=True,
|
||||||
startangle=180,
|
startangle=180,
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import PySimpleGUI as sg
|
|
||||||
from config.bos import bos_config_convert
|
|
||||||
import time
|
|
||||||
from tools.cfg_util.layout import window, update_prog_bar
|
|
||||||
from tools.cfg_util.decorators import disable_buttons
|
|
||||||
from miners.miner_factory import MinerFactory
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from settings import CFG_UTIL_CONFIG_THREADS as CONFIG_THREADS
|
|
||||||
from tools.cfg_util.general import update_miners_data
|
|
||||||
|
|
||||||
|
import PySimpleGUI as sg
|
||||||
|
|
||||||
|
from config import MinerConfig
|
||||||
|
from miners.miner_factory import MinerFactory
|
||||||
|
from settings import CFG_UTIL_CONFIG_THREADS as CONFIG_THREADS
|
||||||
|
from tools.cfg_util.decorators import disable_buttons
|
||||||
|
from tools.cfg_util.general import update_miners_data
|
||||||
|
from tools.cfg_util.layout import window, update_prog_bar
|
||||||
|
|
||||||
progress_bar_len = 0
|
progress_bar_len = 0
|
||||||
|
|
||||||
@@ -20,7 +20,8 @@ async def btn_import(table, selected):
|
|||||||
miner = await MinerFactory().get_miner(ip)
|
miner = await MinerFactory().get_miner(ip)
|
||||||
await miner.get_config()
|
await miner.get_config()
|
||||||
config = miner.config
|
config = miner.config
|
||||||
window["cfg_config_txt"].update(config)
|
if config:
|
||||||
|
window["cfg_config_txt"].update(config.as_yaml())
|
||||||
|
|
||||||
|
|
||||||
@disable_buttons("Configuring")
|
@disable_buttons("Configuring")
|
||||||
@@ -67,7 +68,25 @@ async def send_config_generator(miners: list, config, last_octet_ip_user: bool):
|
|||||||
yield await sent_config
|
yield await sent_config
|
||||||
|
|
||||||
|
|
||||||
def generate_config(username: str, workername: str, v2_allowed: bool):
|
def generate_config(
|
||||||
|
username: str,
|
||||||
|
workername: str,
|
||||||
|
v2_allowed: bool,
|
||||||
|
advanced_cfg: bool,
|
||||||
|
autotuning_enabled: bool,
|
||||||
|
autotuning_wattage: int,
|
||||||
|
manual_fan_control: bool,
|
||||||
|
manual_fan_speed: int,
|
||||||
|
min_fans: int,
|
||||||
|
target_temp: int,
|
||||||
|
hot_temp: int,
|
||||||
|
dangerous_temp: int,
|
||||||
|
dps_enabled: bool,
|
||||||
|
dps_power_step: int,
|
||||||
|
dps_min_power: int,
|
||||||
|
dps_shutdown_enabled: bool,
|
||||||
|
dps_shutdown_duration: int,
|
||||||
|
):
|
||||||
if username and workername:
|
if username and workername:
|
||||||
user = f"{username}.{workername}"
|
user = f"{username}.{workername}"
|
||||||
elif username and not workername:
|
elif username and not workername:
|
||||||
@@ -83,33 +102,67 @@ def generate_config(username: str, workername: str, v2_allowed: bool):
|
|||||||
url_1 = "stratum+tcp://ca.stratum.slushpool.com:3333"
|
url_1 = "stratum+tcp://ca.stratum.slushpool.com:3333"
|
||||||
url_2 = "stratum+tcp://us-east.stratum.slushpool.com:3333"
|
url_2 = "stratum+tcp://us-east.stratum.slushpool.com:3333"
|
||||||
url_3 = "stratum+tcp://stratum.slushpool.com:3333"
|
url_3 = "stratum+tcp://stratum.slushpool.com:3333"
|
||||||
|
if not advanced_cfg:
|
||||||
config = {
|
config = {
|
||||||
"group": [
|
"group": [
|
||||||
{
|
{
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"quota": 1,
|
"quota": 1,
|
||||||
"pool": [
|
"pool": [
|
||||||
{"url": url_1, "user": user, "password": "123"},
|
{"url": url_1, "user": user, "password": "123"},
|
||||||
{"url": url_2, "user": user, "password": "123"},
|
{"url": url_2, "user": user, "password": "123"},
|
||||||
{"url": url_3, "user": user, "password": "123"},
|
{"url": url_3, "user": user, "password": "123"},
|
||||||
],
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"temp_control": {
|
||||||
|
"target_temp": 80.0,
|
||||||
|
"hot_temp": 90.0,
|
||||||
|
"dangerous_temp": 120.0,
|
||||||
|
},
|
||||||
|
"autotuning": {"enabled": True, "psu_power_limit": 900},
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
config = {
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"name": "group",
|
||||||
|
"quota": 1,
|
||||||
|
"pool": [
|
||||||
|
{"url": url_1, "user": user, "password": "123"},
|
||||||
|
{"url": url_2, "user": user, "password": "123"},
|
||||||
|
{"url": url_3, "user": user, "password": "123"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"temp_control": {
|
||||||
|
"mode": "auto",
|
||||||
|
"target_temp": float(target_temp),
|
||||||
|
"hot_temp": float(hot_temp),
|
||||||
|
"dangerous_temp": float(dangerous_temp),
|
||||||
|
},
|
||||||
|
"autotuning": {
|
||||||
|
"enabled": autotuning_enabled,
|
||||||
|
"psu_power_limit": autotuning_wattage,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if manual_fan_control:
|
||||||
|
config["temp_control"]["mode"] = "manual"
|
||||||
|
config["fan_control"] = {}
|
||||||
|
config["fan_control"]["speed"] = manual_fan_speed
|
||||||
|
config["fan_control"]["min_fans"] = min_fans
|
||||||
|
if dps_enabled:
|
||||||
|
config["power_scaling"] = {
|
||||||
|
"enabled": dps_enabled,
|
||||||
|
"power_step": dps_power_step,
|
||||||
|
"min_psu_power_limit": dps_min_power,
|
||||||
|
"shutdown_enabled": dps_shutdown_enabled,
|
||||||
|
"shutdown_duration": dps_shutdown_duration,
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"format": {
|
cfg = MinerConfig().from_raw(config)
|
||||||
"version": "1.2+",
|
|
||||||
"model": "Antminer S9",
|
window["cfg_config_txt"].update(cfg.as_yaml())
|
||||||
"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["cfg_config_txt"].update(bos_config_convert(config))
|
|
||||||
|
|
||||||
|
|
||||||
async def generate_config_ui():
|
async def generate_config_ui():
|
||||||
@@ -126,9 +179,51 @@ async def generate_config_ui():
|
|||||||
values["generate_config_window_username"],
|
values["generate_config_window_username"],
|
||||||
values["generate_config_window_workername"],
|
values["generate_config_window_workername"],
|
||||||
values["generate_config_window_allow_v2"],
|
values["generate_config_window_allow_v2"],
|
||||||
|
values["show_advanced_options"],
|
||||||
|
values["autotuning_enabled"],
|
||||||
|
values["autotuning_wattage"],
|
||||||
|
values["manual_fan_control"],
|
||||||
|
values["manual_fan_speed"],
|
||||||
|
values["min_fans"],
|
||||||
|
values["target_temp"],
|
||||||
|
values["hot_temp"],
|
||||||
|
values["danger_temp"],
|
||||||
|
values["dps_enabled"],
|
||||||
|
values["dps_power_step"],
|
||||||
|
values["dps_min_power"],
|
||||||
|
values["dps_shutdown_enabled"],
|
||||||
|
values["dps_shutdown_duration"],
|
||||||
)
|
)
|
||||||
generate_config_window.close()
|
generate_config_window.close()
|
||||||
break
|
break
|
||||||
|
if event == "show_advanced_options":
|
||||||
|
generate_config_window["advanced_options"].update(
|
||||||
|
visible=values["show_advanced_options"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if event == "autotuning_enabled":
|
||||||
|
generate_config_window["autotuning_wattage"].update(
|
||||||
|
disabled=not values["autotuning_enabled"]
|
||||||
|
)
|
||||||
|
if event == "manual_fan_control":
|
||||||
|
generate_config_window["manual_fan_speed"].update(
|
||||||
|
disabled=not values["manual_fan_control"]
|
||||||
|
)
|
||||||
|
generate_config_window["min_fans"].update(
|
||||||
|
disabled=not values["manual_fan_control"]
|
||||||
|
)
|
||||||
|
if event == "dps_enabled":
|
||||||
|
for elem in ["dps_power_step", "dps_min_power", "dps_shutdown_enabled"]:
|
||||||
|
generate_config_window[elem].update(disabled=not values["dps_enabled"])
|
||||||
|
if not values["dps_enabled"]:
|
||||||
|
generate_config_window["dps_shutdown_duration"].update(disabled=True)
|
||||||
|
if values["dps_enabled"] and values["dps_shutdown_enabled"]:
|
||||||
|
generate_config_window["dps_shutdown_duration"].update(disabled=False)
|
||||||
|
if event == "dps_shutdown_enabled":
|
||||||
|
if values["dps_enabled"]:
|
||||||
|
generate_config_window["dps_shutdown_duration"].update(
|
||||||
|
disabled=not values["dps_shutdown_enabled"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def generate_config_layout():
|
def generate_config_layout():
|
||||||
@@ -155,6 +250,123 @@ def generate_config_layout():
|
|||||||
sg.Text("Allow Stratum V2?:", size=(19, 1)),
|
sg.Text("Allow Stratum V2?:", size=(19, 1)),
|
||||||
sg.Checkbox("", key="generate_config_window_allow_v2", default=True),
|
sg.Checkbox("", key="generate_config_window_allow_v2", default=True),
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
sg.Push(),
|
||||||
|
sg.Checkbox(
|
||||||
|
"Advanced Options", enable_events=True, key="show_advanced_options"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sg.pin(
|
||||||
|
sg.Column(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
sg.Text("Autotuning Enabled:", size=(19, 1)),
|
||||||
|
sg.Checkbox(
|
||||||
|
"", key="autotuning_enabled", enable_events=True
|
||||||
|
),
|
||||||
|
sg.Text("Power Limit:"),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(100, 5001, 100)],
|
||||||
|
initial_value=900,
|
||||||
|
size=(5, 1),
|
||||||
|
key="autotuning_wattage",
|
||||||
|
disabled=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sg.Text("Manual Fan Control:", size=(19, 1)),
|
||||||
|
sg.Checkbox(
|
||||||
|
"", key="manual_fan_control", enable_events=True
|
||||||
|
),
|
||||||
|
sg.Text("Speed:"),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(5, 101, 5)],
|
||||||
|
initial_value=100,
|
||||||
|
size=(5, 1),
|
||||||
|
key="manual_fan_speed",
|
||||||
|
disabled=True,
|
||||||
|
),
|
||||||
|
sg.Text("Min Fans:"),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(5)],
|
||||||
|
initial_value=1,
|
||||||
|
size=(5, 1),
|
||||||
|
key="min_fans",
|
||||||
|
disabled=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sg.Text("Target Temp:", size=(19, 1)),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(5, 101, 5)],
|
||||||
|
initial_value=80,
|
||||||
|
size=(5, 1),
|
||||||
|
key="target_temp",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sg.Text("Hot Temp:", size=(19, 1)),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(5, 111, 5)],
|
||||||
|
initial_value=90,
|
||||||
|
size=(5, 1),
|
||||||
|
key="hot_temp",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sg.Text("Dangerous Temp:", size=(19, 1)),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(5, 131, 5)],
|
||||||
|
initial_value=100,
|
||||||
|
size=(5, 1),
|
||||||
|
key="danger_temp",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sg.Text("Dynamic Power Scaling:"),
|
||||||
|
sg.Checkbox("", key="dps_enabled", enable_events=True),
|
||||||
|
sg.Text("Power Step:"),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(50, 301, 5)],
|
||||||
|
initial_value=100,
|
||||||
|
size=(5, 1),
|
||||||
|
key="dps_power_step",
|
||||||
|
disabled=True,
|
||||||
|
),
|
||||||
|
sg.Text("Min Power:"),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(100, 5001, 100)],
|
||||||
|
initial_value=800,
|
||||||
|
size=(5, 1),
|
||||||
|
key="dps_min_power",
|
||||||
|
disabled=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sg.Text("DPS Shutdown:"),
|
||||||
|
sg.Checkbox(
|
||||||
|
"",
|
||||||
|
key="dps_shutdown_enabled",
|
||||||
|
enable_events=True,
|
||||||
|
disabled=True,
|
||||||
|
),
|
||||||
|
sg.Text("Shutdown Duration (H):"),
|
||||||
|
sg.Spin(
|
||||||
|
[i for i in range(1, 11, 1)],
|
||||||
|
initial_value=3,
|
||||||
|
size=(5, 1),
|
||||||
|
key="dps_shutdown_duration",
|
||||||
|
disabled=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
key="advanced_options",
|
||||||
|
visible=False,
|
||||||
|
pad=0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
[sg.Button("Generate", key="generate_config_window_generate")],
|
[sg.Button("Generate", key="generate_config_window_generate")],
|
||||||
]
|
]
|
||||||
return config_layout
|
return config_layout
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import aiohttp
|
|
||||||
import httpx
|
|
||||||
import shutil
|
|
||||||
import aiofiles
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
|
import httpx
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
|
||||||
async def get_latest_version(session):
|
async def get_latest_version(session):
|
||||||
|
|||||||
Reference in New Issue
Block a user