Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
896968dded | ||
|
|
56b8f7c5b3 | ||
|
|
0ed7559aef | ||
|
|
275d87e4fe | ||
|
|
c3ab814d77 | ||
|
|
05a8569205 | ||
|
|
b098cb8136 | ||
|
|
75fe7857e4 | ||
|
|
66797aced1 | ||
|
|
4a71e38078 | ||
|
|
9fb07e4fa3 | ||
|
|
74792771ec | ||
|
|
fa6e8a976d | ||
|
|
f20531cff5 | ||
|
|
8b1cbed9ce | ||
|
|
0194e13427 | ||
|
|
82d71abf54 | ||
|
|
e71cfadf6e | ||
|
|
18931c4e98 | ||
|
|
8622c080aa | ||
|
|
cb71b2a593 | ||
|
|
ff5956da41 | ||
|
|
acdafc2efd | ||
|
|
b8874092ad |
@@ -1,3 +1,6 @@
|
||||
ci:
|
||||
skip:
|
||||
- unittest
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
@@ -24,4 +27,3 @@ repos:
|
||||
'types': [python]
|
||||
args: ["-p '*test.py'"] # Probably this option is absolutely not needed.
|
||||
pass_filenames: false
|
||||
stages: [commit]
|
||||
|
||||
@@ -29,6 +29,13 @@
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## T21 (BOS+)
|
||||
::: pyasic.miners.antminer.bosminer.X21.T21.BOSMinerT21
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## S21 (VNish)
|
||||
::: pyasic.miners.antminer.vnish.X21.S21.VNishS21
|
||||
handler: python
|
||||
|
||||
@@ -22,6 +22,20 @@
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KA3 (Stock)
|
||||
::: pyasic.miners.antminer.bmminer.X3.KA3.BMMinerKA3
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KS3 (Stock)
|
||||
::: pyasic.miners.antminer.bmminer.X3.KS3.BMMinerKS3
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## L3+ (VNish)
|
||||
::: pyasic.miners.antminer.vnish.X3.L3.VnishL3Plus
|
||||
handler: python
|
||||
|
||||
@@ -8,3 +8,10 @@
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KS5 (Stock)
|
||||
::: pyasic.miners.antminer.bmminer.X5.KS5.BMMinerKS5
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
# pyasic
|
||||
## KSX Models
|
||||
|
||||
## KS0 (Stock)
|
||||
::: pyasic.miners.iceriver.iceminer.KSX.KS0.IceRiverKS0
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KS1 (Stock)
|
||||
::: pyasic.miners.iceriver.iceminer.KSX.KS1.IceRiverKS1
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KS2 (Stock)
|
||||
::: pyasic.miners.iceriver.iceminer.KSX.KS2.IceRiverKS2
|
||||
handler: python
|
||||
@@ -8,3 +22,24 @@
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KS3 (Stock)
|
||||
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KS3L (Stock)
|
||||
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3L
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## KS3M (Stock)
|
||||
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3M
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
|
||||
@@ -21,12 +21,15 @@ details {
|
||||
<li><a href="../antminer/X3#d3-stock">D3 (Stock)</a></li>
|
||||
<li><a href="../antminer/X3#hs3-stock">HS3 (Stock)</a></li>
|
||||
<li><a href="../antminer/X3#l3_1-stock">L3+ (Stock)</a></li>
|
||||
<li><a href="../antminer/X3#ka3-stock">KA3 (Stock)</a></li>
|
||||
<li><a href="../antminer/X3#ks3-stock">KS3 (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
<summary>X5 Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../antminer/X5#dr5-stock">DR5 (Stock)</a></li>
|
||||
<li><a href="../antminer/X5#ks5-stock">KS5 (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
@@ -378,6 +381,12 @@ details {
|
||||
<li><a href="../avalonminer/A12X#avalon-1246-stock">Avalon 1246 (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
<summary>nano Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../avalonminer/nano#avalon-nano-3-stock">Avalon Nano 3 (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
@@ -395,6 +404,12 @@ details {
|
||||
<li><a href="../innosilicon/A10X#a10x-stock">A10X (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
<summary>A11X Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../innosilicon/A11X#a11mx-stock">A11MX (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
@@ -470,6 +485,7 @@ details {
|
||||
<summary>X21 Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../antminer/X21#s21-bos_1">S21 (BOS+)</a></li>
|
||||
<li><a href="../antminer/X21#t21-bos_1">T21 (BOS+)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
</ul>
|
||||
@@ -661,7 +677,12 @@ details {
|
||||
<details>
|
||||
<summary>KSX Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../iceriver/KSX#ks0-stock">KS0 (Stock)</a></li>
|
||||
<li><a href="../iceriver/KSX#ks1-stock">KS1 (Stock)</a></li>
|
||||
<li><a href="../iceriver/KSX#ks2-stock">KS2 (Stock)</a></li>
|
||||
<li><a href="../iceriver/KSX#ks3-stock">KS3 (Stock)</a></li>
|
||||
<li><a href="../iceriver/KSX#ks3l-stock">KS3L (Stock)</a></li>
|
||||
<li><a href="../iceriver/KSX#ks3m-stock">KS3M (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
</ul>
|
||||
|
||||
@@ -250,3 +250,9 @@ class MinerConfig:
|
||||
pools=PoolConfig.from_bitaxe(web_system_info),
|
||||
fan_mode=FanModeConfig.from_bitaxe(web_system_info),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_iceriver(cls, web_userpanel: dict) -> "MinerConfig":
|
||||
return cls(
|
||||
pools=PoolConfig.from_iceriver(web_userpanel),
|
||||
)
|
||||
|
||||
@@ -222,6 +222,14 @@ class Pool(MinerConfigValue):
|
||||
password=web_system_info.get("stratumPassword", ""),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_iceriver(cls, web_pool: dict) -> "Pool":
|
||||
return cls(
|
||||
url=web_pool["addr"],
|
||||
user=web_pool["user"],
|
||||
password=web_pool["pass"],
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PoolGroup(MinerConfigValue):
|
||||
@@ -402,6 +410,15 @@ class PoolGroup(MinerConfigValue):
|
||||
def from_bitaxe(cls, web_system_info: dict) -> "PoolGroup":
|
||||
return cls(pools=[Pool.from_bitaxe(web_system_info)])
|
||||
|
||||
@classmethod
|
||||
def from_iceriver(cls, web_userpanel: dict) -> "PoolGroup":
|
||||
return cls(
|
||||
pools=[
|
||||
Pool.from_iceriver(web_pool)
|
||||
for web_pool in web_userpanel["data"]["pools"]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PoolConfig(MinerConfigValue):
|
||||
@@ -568,3 +585,7 @@ class PoolConfig(MinerConfigValue):
|
||||
@classmethod
|
||||
def from_bitaxe(cls, web_system_info: dict) -> "PoolConfig":
|
||||
return cls(groups=[PoolGroup.from_bitaxe(web_system_info)])
|
||||
|
||||
@classmethod
|
||||
def from_iceriver(cls, web_userpanel: dict) -> "PoolConfig":
|
||||
return cls(groups=[PoolGroup.from_iceriver(web_userpanel)])
|
||||
|
||||
@@ -23,13 +23,13 @@ from typing import Any, List, Union
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.config.mining import MiningModePowerTune
|
||||
from pyasic.data.pools import PoolMetrics
|
||||
|
||||
from .boards import HashBoard
|
||||
from .device import DeviceInfo
|
||||
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
|
||||
from .fans import Fan
|
||||
from .hashrate import AlgoHashRate, HashUnit
|
||||
from pyasic.data.pools import PoolMetrics
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -89,6 +89,8 @@ class PoolMetrics:
|
||||
@staticmethod
|
||||
def _calculate_percentage(value: int, total: int) -> float:
|
||||
"""Calculate the percentage."""
|
||||
if value is None or total is None:
|
||||
return 0
|
||||
if total == 0:
|
||||
return 0
|
||||
return (value / total) * 100
|
||||
|
||||
@@ -23,6 +23,7 @@ from .S19 import (
|
||||
BMMinerS19j,
|
||||
BMMinerS19jNoPIC,
|
||||
BMMinerS19jPro,
|
||||
BMMinerS19KPro,
|
||||
BMMinerS19L,
|
||||
BMMinerS19Plus,
|
||||
BMMinerS19Pro,
|
||||
@@ -30,6 +31,5 @@ from .S19 import (
|
||||
BMMinerS19ProPlus,
|
||||
BMMinerS19ProPlusHydro,
|
||||
BMMinerS19XP,
|
||||
BMMinerS19KPro,
|
||||
)
|
||||
from .T19 import BMMinerT19
|
||||
|
||||
@@ -15,7 +15,4 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from .S21 import ePICS21, ePICS21Pro
|
||||
|
||||
from .T21 import (
|
||||
ePICT21,
|
||||
)
|
||||
from .T21 import ePICT21
|
||||
|
||||
@@ -597,49 +597,44 @@ class AntminerOld(CGMiner):
|
||||
pass
|
||||
|
||||
if rpc_stats is not None:
|
||||
try:
|
||||
board_offset = -1
|
||||
boards = rpc_stats["STATS"]
|
||||
if len(boards) > 1:
|
||||
for board_num in range(1, 16, 5):
|
||||
for _b_num in range(5):
|
||||
b = boards[1].get(f"chain_acn{board_num + _b_num}")
|
||||
board_offset = -1
|
||||
boards = rpc_stats["STATS"]
|
||||
if len(boards) > 1:
|
||||
for board_num in range(1, 16, 5):
|
||||
for _b_num in range(5):
|
||||
b = boards[1].get(f"chain_acn{board_num + _b_num}")
|
||||
|
||||
if b and not b == 0 and board_offset == -1:
|
||||
board_offset = board_num
|
||||
if board_offset == -1:
|
||||
board_offset = 1
|
||||
if b and not b == 0 and board_offset == -1:
|
||||
board_offset = board_num
|
||||
if board_offset == -1:
|
||||
board_offset = 1
|
||||
|
||||
for i in range(
|
||||
board_offset, board_offset + self.expected_hashboards
|
||||
):
|
||||
hashboard = HashBoard(
|
||||
slot=i - board_offset, expected_chips=self.expected_chips
|
||||
)
|
||||
for i in range(board_offset, board_offset + self.expected_hashboards):
|
||||
hashboard = HashBoard(
|
||||
slot=i - board_offset, expected_chips=self.expected_chips
|
||||
)
|
||||
|
||||
chip_temp = boards[1].get(f"temp{i}")
|
||||
if chip_temp:
|
||||
hashboard.chip_temp = round(chip_temp)
|
||||
chip_temp = boards[1].get(f"temp{i}")
|
||||
if chip_temp:
|
||||
hashboard.chip_temp = round(chip_temp)
|
||||
|
||||
temp = boards[1].get(f"temp2_{i}")
|
||||
if temp:
|
||||
hashboard.temp = round(temp)
|
||||
temp = boards[1].get(f"temp2_{i}")
|
||||
if temp:
|
||||
hashboard.temp = round(temp)
|
||||
|
||||
hashrate = boards[1].get(f"chain_rate{i}")
|
||||
if hashrate:
|
||||
hashboard.hashrate = AlgoHashRate.SHA256(
|
||||
hashrate, HashUnit.SHA256.GH
|
||||
).into(self.algo.unit.default)
|
||||
hashrate = boards[1].get(f"chain_rate{i}")
|
||||
if hashrate:
|
||||
hashboard.hashrate = AlgoHashRate.SHA256(
|
||||
float(hashrate), HashUnit.SHA256.GH
|
||||
).into(self.algo.unit.default)
|
||||
|
||||
chips = boards[1].get(f"chain_acn{i}")
|
||||
if chips:
|
||||
hashboard.chips = chips
|
||||
hashboard.missing = False
|
||||
if (not chips) or (not chips > 0):
|
||||
hashboard.missing = True
|
||||
hashboards.append(hashboard)
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
chips = boards[1].get(f"chain_acn{i}")
|
||||
if chips:
|
||||
hashboard.chips = chips
|
||||
hashboard.missing = False
|
||||
if (not chips) or (not chips > 0):
|
||||
hashboard.missing = True
|
||||
hashboards.append(hashboard)
|
||||
|
||||
return hashboards
|
||||
|
||||
|
||||
@@ -193,7 +193,14 @@ class Auradine(StockFirmware):
|
||||
for key in conf.keys():
|
||||
await self.web.send_command(command=key, **conf[key])
|
||||
|
||||
async def upgrade_firmware(self, *, url: str = None, version: str = "latest", keep_settings: bool = False, **kwargs) -> bool:
|
||||
async def upgrade_firmware(
|
||||
self,
|
||||
*,
|
||||
url: str = None,
|
||||
version: str = "latest",
|
||||
keep_settings: bool = False,
|
||||
**kwargs,
|
||||
) -> bool:
|
||||
"""
|
||||
Upgrade the firmware of the Auradine device.
|
||||
|
||||
@@ -209,7 +216,9 @@ class Auradine(StockFirmware):
|
||||
logging.info("Starting firmware upgrade process.")
|
||||
|
||||
if not url and not version:
|
||||
raise ValueError("Either URL or version must be provided for firmware upgrade.")
|
||||
raise ValueError(
|
||||
"Either URL or version must be provided for firmware upgrade."
|
||||
)
|
||||
|
||||
if url:
|
||||
result = await self.web.firmware_upgrade(url=url)
|
||||
@@ -220,11 +229,15 @@ class Auradine(StockFirmware):
|
||||
logging.info("Firmware upgrade process completed successfully.")
|
||||
return True
|
||||
else:
|
||||
logging.error(f"Firmware upgrade failed: {result.get('error', 'Unknown error')}")
|
||||
logging.error(
|
||||
f"Firmware upgrade failed: {result.get('error', 'Unknown error')}"
|
||||
)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"An error occurred during the firmware upgrade process: {str(e)}")
|
||||
logging.error(
|
||||
f"An error occurred during the firmware upgrade process: {str(e)}"
|
||||
)
|
||||
return False
|
||||
|
||||
##################################################
|
||||
|
||||
@@ -18,11 +18,11 @@ from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||
from pyasic.miners.device.firmware import StockFirmware
|
||||
from pyasic.rpc.bfgminer import BFGMinerRPCAPI
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
|
||||
BFGMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
@@ -263,4 +263,4 @@ class BFGMiner(StockFirmware):
|
||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
||||
).into(self.algo.unit.default)
|
||||
except LookupError:
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -23,11 +23,11 @@ import aiofiles
|
||||
from pyasic.config import MinerConfig, MiningModeConfig
|
||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||
from pyasic.miners.device.firmware import StockFirmware
|
||||
from pyasic.rpc.btminer import BTMinerRPCAPI
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
|
||||
BTMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
@@ -113,7 +113,7 @@ BTMINER_DATA_LOC = DataLocations(
|
||||
str(DataOptions.POOLS): DataFunction(
|
||||
"_get_pools",
|
||||
[RPCAPICommand("rpc_pools", "pools")],
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from typing import Optional, List
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import AlgoHashRate, HashUnit
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||
from pyasic.miners.device.firmware import StockFirmware
|
||||
from pyasic.rpc.cgminer import CGMinerRPCAPI
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
|
||||
CGMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
|
||||
@@ -454,8 +454,9 @@ class ePIC(ePICFirmware):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def upgrade_firmware(self, file: Path | str, keep_settings: bool = True) -> bool:
|
||||
|
||||
async def upgrade_firmware(
|
||||
self, file: Path | str, keep_settings: bool = True
|
||||
) -> bool:
|
||||
"""
|
||||
Upgrade the firmware of the ePIC miner device.
|
||||
|
||||
@@ -466,4 +467,4 @@ class ePIC(ePICFirmware):
|
||||
Returns:
|
||||
bool: Whether the firmware update succeeded.
|
||||
"""
|
||||
return await self.web.system_update(file=file, keep_settings=keep_settings)
|
||||
return await self.web.system_update(file=file, keep_settings=keep_settings)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic import MinerConfig
|
||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
from pyasic.device import MinerAlgo
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||
@@ -41,6 +43,10 @@ ICERIVER_DATA_LOC = DataLocations(
|
||||
"_get_uptime",
|
||||
[WebAPICommand("web_userpanel", "userpanel")],
|
||||
),
|
||||
str(DataOptions.POOLS): DataFunction(
|
||||
"_get_pools",
|
||||
[WebAPICommand("web_userpanel", "userpanel")],
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -67,6 +73,11 @@ class IceRiver(StockFirmware):
|
||||
return False
|
||||
return True
|
||||
|
||||
async def get_config(self) -> MinerConfig:
|
||||
web_userpanel = await self.web.userpanel()
|
||||
|
||||
return MinerConfig.from_iceriver(web_userpanel)
|
||||
|
||||
async def _get_fans(self, web_userpanel: dict = None) -> List[Fan]:
|
||||
if web_userpanel is None:
|
||||
try:
|
||||
@@ -76,7 +87,7 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
return [Fan(spd) for spd in web_userpanel["fans"]]
|
||||
return [Fan(spd) for spd in web_userpanel["userpanel"]["data"]["fans"]]
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
@@ -89,7 +100,9 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
return web_userpanel["mac"].upper().replace("-", ":")
|
||||
return (
|
||||
web_userpanel["userpanel"]["data"]["mac"].upper().replace("-", ":")
|
||||
)
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
@@ -102,7 +115,7 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
return web_userpanel["host"]
|
||||
return web_userpanel["userpanel"]["data"]["host"]
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
@@ -115,9 +128,13 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
base_unit = web_userpanel["unit"]
|
||||
base_unit = web_userpanel["userpanel"]["data"]["unit"]
|
||||
return AlgoHashRate.SHA256(
|
||||
float(web_userpanel["rtpow"].replace(base_unit, "")),
|
||||
float(
|
||||
web_userpanel["userpanel"]["data"]["rtpow"].replace(
|
||||
base_unit, ""
|
||||
)
|
||||
),
|
||||
unit=MinerAlgo.SHA256.unit.from_str(base_unit + "H"),
|
||||
).into(MinerAlgo.SHA256.unit.default)
|
||||
except (LookupError, ValueError, TypeError):
|
||||
@@ -132,7 +149,7 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
return web_userpanel["locate"]
|
||||
return web_userpanel["userpanel"]["data"]["locate"]
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
return False
|
||||
@@ -146,7 +163,7 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
return web_userpanel["powstate"]
|
||||
return web_userpanel["userpanel"]["data"]["powstate"]
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
@@ -164,7 +181,7 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
for board in web_userpanel["boards"]:
|
||||
for board in web_userpanel["userpanel"]["data"]["boards"]:
|
||||
idx = int(board["no"] - 1)
|
||||
hb_list[idx].chip_temp = round(board["outtmp"])
|
||||
hb_list[idx].temp = round(board["intmp"])
|
||||
@@ -186,7 +203,7 @@ class IceRiver(StockFirmware):
|
||||
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
runtime = web_userpanel["runtime"]
|
||||
runtime = web_userpanel["userpanel"]["data"]["runtime"]
|
||||
days, hours, minutes, seconds = runtime.split(":")
|
||||
return (
|
||||
(int(days) * 24 * 60 * 60)
|
||||
@@ -196,3 +213,36 @@ class IceRiver(StockFirmware):
|
||||
)
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def _get_pools(self, web_userpanel: dict = None) -> List[PoolMetrics]:
|
||||
if web_userpanel is None:
|
||||
try:
|
||||
web_userpanel = await self.web.userpanel()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
pools_data = []
|
||||
if web_userpanel is not None:
|
||||
try:
|
||||
pools = web_userpanel["userpanel"]["data"]["pools"]
|
||||
for pool_info in pools:
|
||||
pool_num = pool_info.get("no")
|
||||
if pool_num is not None:
|
||||
pool_num = int(pool_num)
|
||||
if pool_info["addr"] == "":
|
||||
continue
|
||||
url = pool_info.get("addr")
|
||||
pool_url = PoolUrl.from_str(url) if url else None
|
||||
pool_data = PoolMetrics(
|
||||
accepted=pool_info.get("accepted"),
|
||||
rejected=pool_info.get("rejected"),
|
||||
active=pool_info.get("connect"),
|
||||
alive=int(pool_info.get("state", 0)) == 1,
|
||||
url=pool_url,
|
||||
user=pool_info.get("user"),
|
||||
index=pool_num,
|
||||
)
|
||||
pools_data.append(pool_data)
|
||||
except LookupError:
|
||||
pass
|
||||
return pools_data
|
||||
|
||||
@@ -19,6 +19,7 @@ from pyasic.config import MinerConfig
|
||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.data.error_codes.innosilicon import InnosiliconError
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.backends import CGMiner
|
||||
from pyasic.miners.data import (
|
||||
@@ -29,7 +30,6 @@ from pyasic.miners.data import (
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.web.innosilicon import InnosiliconWebAPI
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
|
||||
INNOSILICON_DATA_LOC = DataLocations(
|
||||
**{
|
||||
@@ -92,9 +92,8 @@ INNOSILICON_DATA_LOC = DataLocations(
|
||||
[RPCAPICommand("rpc_stats", "stats")],
|
||||
),
|
||||
str(DataOptions.POOLS): DataFunction(
|
||||
"_get_pools",
|
||||
[RPCAPICommand("rpc_pools", "pools")]
|
||||
)
|
||||
"_get_pools", [RPCAPICommand("rpc_pools", "pools")]
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -116,7 +115,7 @@ class Innosilicon(CGMiner):
|
||||
except APIError:
|
||||
return self.config
|
||||
|
||||
self.config = MinerConfig.from_inno([pools])
|
||||
self.config = MinerConfig.from_inno(pools["pools"])
|
||||
return self.config
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||
|
||||
@@ -3,13 +3,13 @@ from typing import List, Optional
|
||||
from pyasic import MinerConfig
|
||||
from pyasic.config import MiningModeConfig
|
||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||
from pyasic.miners.device.firmware import MaraFirmware
|
||||
from pyasic.misc import merge_dicts
|
||||
from pyasic.rpc.marathon import MaraRPCAPI
|
||||
from pyasic.web.marathon import MaraWebAPI
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
|
||||
MARA_DATA_LOC = DataLocations(
|
||||
**{
|
||||
@@ -319,10 +319,13 @@ class MaraMiner(MaraFirmware):
|
||||
return []
|
||||
|
||||
active_pool_index = None
|
||||
highest_priority = float('inf')
|
||||
highest_priority = float("inf")
|
||||
|
||||
for pool_info in web_pools:
|
||||
if pool_info.get("status") == "Alive" and pool_info.get("priority", float('inf')) < highest_priority:
|
||||
if (
|
||||
pool_info.get("status") == "Alive"
|
||||
and pool_info.get("priority", float("inf")) < highest_priority
|
||||
):
|
||||
highest_priority = pool_info.get["priority"]
|
||||
active_pool_index = pool_info["index"]
|
||||
|
||||
|
||||
@@ -560,7 +560,14 @@ class BaseMiner(MinerProtocol):
|
||||
if self._ssh_cls is not None:
|
||||
self.ssh = self._ssh_cls(ip)
|
||||
|
||||
async def upgrade_firmware(self, *, file: str = None, url: str = None, version: str = None, keep_settings: bool = True) -> bool:
|
||||
async def upgrade_firmware(
|
||||
self,
|
||||
*,
|
||||
file: str = None,
|
||||
url: str = None,
|
||||
version: str = None,
|
||||
keep_settings: bool = True,
|
||||
) -> bool:
|
||||
"""Upgrade the firmware of the miner.
|
||||
|
||||
Parameters:
|
||||
@@ -574,4 +581,5 @@ class BaseMiner(MinerProtocol):
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
AnyMiner = TypeVar("AnyMiner", bound=BaseMiner)
|
||||
|
||||
@@ -14,7 +14,4 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from .blockminer import (
|
||||
ePICBlockMiner520i,
|
||||
ePICBlockMiner720i,
|
||||
)
|
||||
from .blockminer import ePICBlockMiner520i, ePICBlockMiner720i
|
||||
|
||||
@@ -43,4 +43,4 @@ class LuxOSFirmware(BaseMiner):
|
||||
|
||||
|
||||
class MaraFirmware(BaseMiner):
|
||||
firmware = MinerFirmware.MARATHON
|
||||
firmware = MinerFirmware.MARATHON
|
||||
|
||||
@@ -19,3 +19,6 @@ from pyasic.miners.device.makes import InnosiliconMake
|
||||
|
||||
class A11MX(InnosiliconMake):
|
||||
raw_model = MinerModel.INNOSILICON.A11MX
|
||||
|
||||
expected_hashboards = 4
|
||||
expected_chips = 8
|
||||
|
||||
@@ -546,6 +546,7 @@ class MinerFactory:
|
||||
MinerTypes.AURADINE: self.get_miner_model_auradine,
|
||||
MinerTypes.MARATHON: self.get_miner_model_marathon,
|
||||
MinerTypes.BITAXE: self.get_miner_model_bitaxe,
|
||||
MinerTypes.ICERIVER: self.get_miner_model_iceriver,
|
||||
}
|
||||
fn = miner_model_fns.get(miner_type)
|
||||
|
||||
@@ -941,10 +942,19 @@ class MinerFactory:
|
||||
async with httpx.AsyncClient(transport=settings.transport()) as session:
|
||||
auth_req = await session.post(
|
||||
f"http://{ip}/api/auth",
|
||||
data={"username": "admin", "password": "admin"},
|
||||
data={
|
||||
"username": "admin",
|
||||
"password": settings.get(
|
||||
"default_innosilicon_web_password", "admin"
|
||||
),
|
||||
},
|
||||
)
|
||||
auth = auth_req.json()["jwt"]
|
||||
except (httpx.HTTPError, LookupError):
|
||||
return
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(transport=settings.transport()) as session:
|
||||
web_data = (
|
||||
await session.post(
|
||||
f"http://{ip}/api/type",
|
||||
@@ -955,6 +965,18 @@ class MinerFactory:
|
||||
return web_data["type"]
|
||||
except (httpx.HTTPError, LookupError):
|
||||
pass
|
||||
try:
|
||||
async with httpx.AsyncClient(transport=settings.transport()) as session:
|
||||
web_data = (
|
||||
await session.post(
|
||||
f"http://{ip}/overview",
|
||||
headers={"Authorization": "Bearer " + auth},
|
||||
data={},
|
||||
)
|
||||
).json()
|
||||
return web_data["type"]
|
||||
except (httpx.HTTPError, LookupError):
|
||||
pass
|
||||
|
||||
async def get_miner_model_braiins_os(self, ip: str) -> str | None:
|
||||
sock_json_data = await self.send_api_command(ip, "devdetails")
|
||||
|
||||
@@ -22,8 +22,8 @@ import hashlib
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from typing import Literal, Union
|
||||
import struct
|
||||
from typing import Literal, Union
|
||||
|
||||
import httpx
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
|
||||
@@ -757,4 +757,4 @@ class LUXMinerRPCAPI(BaseMinerRPCAPI):
|
||||
Returns:
|
||||
The response from the miner after sending the 'updaterun' command.
|
||||
"""
|
||||
return await self.send_command("updaterun")
|
||||
return await self.send_command("updaterun")
|
||||
|
||||
@@ -17,10 +17,11 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import aiofiles
|
||||
import httpx
|
||||
from pathlib import Path
|
||||
|
||||
from pyasic import settings
|
||||
from pyasic.web.base import BaseWebAPI
|
||||
@@ -414,10 +415,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
||||
parameters = {
|
||||
"file": (file.name, file_content, "application/octet-stream"),
|
||||
"filename": file.name,
|
||||
"keep_settings": keep_settings
|
||||
"keep_settings": keep_settings,
|
||||
}
|
||||
|
||||
return await self.send_command(
|
||||
command="upgrade",
|
||||
**parameters
|
||||
)
|
||||
return await self.send_command(command="upgrade", **parameters)
|
||||
|
||||
@@ -4,17 +4,12 @@
|
||||
# This file has been @generated
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Dict,
|
||||
Optional,
|
||||
)
|
||||
from typing import TYPE_CHECKING, Dict, Optional
|
||||
|
||||
import betterproto
|
||||
import grpclib
|
||||
from betterproto.grpc.grpclib_server import ServiceBase
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import grpclib.server
|
||||
from betterproto.grpc.grpclib_client import MetadataLike
|
||||
|
||||
@@ -5,19 +5,12 @@
|
||||
import warnings
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
AsyncIterator,
|
||||
Dict,
|
||||
List,
|
||||
Optional,
|
||||
)
|
||||
from typing import TYPE_CHECKING, AsyncIterator, Dict, List, Optional
|
||||
|
||||
import betterproto
|
||||
import grpclib
|
||||
from betterproto.grpc.grpclib_server import ServiceBase
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import grpclib.server
|
||||
from betterproto.grpc.grpclib_client import MetadataLike
|
||||
|
||||
@@ -127,6 +127,9 @@ class InnosiliconWebAPI(BaseWebAPI):
|
||||
async def get_all(self) -> dict:
|
||||
return await self.send_command("getAll")
|
||||
|
||||
async def summary(self) -> dict:
|
||||
return await self.send_command("summary")
|
||||
|
||||
async def get_error_detail(self) -> dict:
|
||||
return await self.send_command("getErrorDetail")
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "pyasic"
|
||||
version = "0.61.4"
|
||||
version = "0.61.13"
|
||||
description = "A simplified and standardized interface for Bitcoin ASICs."
|
||||
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
||||
repository = "https://github.com/UpstreamData/pyasic"
|
||||
|
||||
Reference in New Issue
Block a user