Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d67de98bd0 | ||
|
|
fd1a3e459b | ||
|
|
adcab694b5 | ||
|
|
2bb097272f | ||
|
|
896968dded | ||
|
|
56b8f7c5b3 | ||
|
|
0ed7559aef | ||
|
|
275d87e4fe | ||
|
|
c3ab814d77 | ||
|
|
05a8569205 | ||
|
|
b098cb8136 | ||
|
|
75fe7857e4 | ||
|
|
66797aced1 | ||
|
|
4a71e38078 | ||
|
|
9fb07e4fa3 | ||
|
|
74792771ec | ||
|
|
fa6e8a976d | ||
|
|
f20531cff5 | ||
|
|
8b1cbed9ce | ||
|
|
0194e13427 |
@@ -1,3 +1,6 @@
|
|||||||
|
ci:
|
||||||
|
skip:
|
||||||
|
- unittest
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.5.0
|
rev: v4.5.0
|
||||||
@@ -24,4 +27,3 @@ repos:
|
|||||||
'types': [python]
|
'types': [python]
|
||||||
args: ["-p '*test.py'"] # Probably this option is absolutely not needed.
|
args: ["-p '*test.py'"] # Probably this option is absolutely not needed.
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
stages: [commit]
|
|
||||||
|
|||||||
24
poetry.lock
generated
24
poetry.lock
generated
@@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aiofiles"
|
name = "aiofiles"
|
||||||
@@ -62,21 +62,25 @@ name = "betterproto"
|
|||||||
version = "2.0.0b7"
|
version = "2.0.0b7"
|
||||||
description = "A better Protobuf / gRPC generator & library"
|
description = "A better Protobuf / gRPC generator & library"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "<4.0,>=3.7"
|
python-versions = "^3.7"
|
||||||
files = [
|
files = []
|
||||||
{file = "betterproto-2.0.0b7-py3-none-any.whl", hash = "sha256:401ab8055e2f814e77b9c88a74d0e1ae3d1e8a969cced6aeb1b59f71ad63fbd2"},
|
develop = false
|
||||||
{file = "betterproto-2.0.0b7.tar.gz", hash = "sha256:1b1458ca5278d519bcd62556a4c236f998a91d503f0f71c67b0b954747052af2"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
grpclib = ">=0.4.1,<0.5.0"
|
grpclib = "^0.4.1"
|
||||||
python-dateutil = ">=2.8,<3.0"
|
python-dateutil = "^2.8"
|
||||||
typing-extensions = ">=4.7.1,<5.0.0"
|
typing-extensions = "^4.7.1"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
compiler = ["black (>=23.1.0)", "isort (>=5.11.5,<6.0.0)", "jinja2 (>=3.0.3)"]
|
compiler = ["black (>=23.1.0)", "isort (>=5.11.5,<6.0.0)", "jinja2 (>=3.0.3)"]
|
||||||
rust-codec = ["betterproto-rust-codec (==0.1.1)"]
|
rust-codec = ["betterproto-rust-codec (==0.1.1)"]
|
||||||
|
|
||||||
|
[package.source]
|
||||||
|
type = "git"
|
||||||
|
url = "https://github.com/danielgtaylor/python-betterproto"
|
||||||
|
reference = "v.2.0.0b7"
|
||||||
|
resolved_reference = "1538e156a1eadb88799eca009a238093d6bb40df"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2024.8.30"
|
version = "2024.8.30"
|
||||||
@@ -1183,4 +1187,4 @@ type = ["pytest-mypy"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "d611b5e8b0c5611d6ee916cedfb7f07f20dfc90a675ebaed04188e8b3c96aabe"
|
content-hash = "503e85a8a0f1720b55634c5706cc6c2f4fbe8d14eb9b585ffce7e1e81811a70d"
|
||||||
|
|||||||
@@ -250,3 +250,9 @@ class MinerConfig:
|
|||||||
pools=PoolConfig.from_bitaxe(web_system_info),
|
pools=PoolConfig.from_bitaxe(web_system_info),
|
||||||
fan_mode=FanModeConfig.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", ""),
|
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
|
@dataclass
|
||||||
class PoolGroup(MinerConfigValue):
|
class PoolGroup(MinerConfigValue):
|
||||||
@@ -402,6 +410,15 @@ class PoolGroup(MinerConfigValue):
|
|||||||
def from_bitaxe(cls, web_system_info: dict) -> "PoolGroup":
|
def from_bitaxe(cls, web_system_info: dict) -> "PoolGroup":
|
||||||
return cls(pools=[Pool.from_bitaxe(web_system_info)])
|
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
|
@dataclass
|
||||||
class PoolConfig(MinerConfigValue):
|
class PoolConfig(MinerConfigValue):
|
||||||
@@ -568,3 +585,7 @@ class PoolConfig(MinerConfigValue):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_bitaxe(cls, web_system_info: dict) -> "PoolConfig":
|
def from_bitaxe(cls, web_system_info: dict) -> "PoolConfig":
|
||||||
return cls(groups=[PoolGroup.from_bitaxe(web_system_info)])
|
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 import MinerConfig
|
||||||
from pyasic.config.mining import MiningModePowerTune
|
from pyasic.config.mining import MiningModePowerTune
|
||||||
|
from pyasic.data.pools import PoolMetrics
|
||||||
|
|
||||||
from .boards import HashBoard
|
from .boards import HashBoard
|
||||||
from .device import DeviceInfo
|
from .device import DeviceInfo
|
||||||
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
|
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
|
||||||
from .fans import Fan
|
from .fans import Fan
|
||||||
from .hashrate import AlgoHashRate, HashUnit
|
from .hashrate import AlgoHashRate, HashUnit
|
||||||
from pyasic.data.pools import PoolMetrics
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ class PoolMetrics:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _calculate_percentage(value: int, total: int) -> float:
|
def _calculate_percentage(value: int, total: int) -> float:
|
||||||
"""Calculate the percentage."""
|
"""Calculate the percentage."""
|
||||||
|
if value is None or total is None:
|
||||||
|
return 0
|
||||||
if total == 0:
|
if total == 0:
|
||||||
return 0
|
return 0
|
||||||
return (value / total) * 100
|
return (value / total) * 100
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from .S19 import (
|
|||||||
BMMinerS19j,
|
BMMinerS19j,
|
||||||
BMMinerS19jNoPIC,
|
BMMinerS19jNoPIC,
|
||||||
BMMinerS19jPro,
|
BMMinerS19jPro,
|
||||||
|
BMMinerS19KPro,
|
||||||
BMMinerS19L,
|
BMMinerS19L,
|
||||||
BMMinerS19Plus,
|
BMMinerS19Plus,
|
||||||
BMMinerS19Pro,
|
BMMinerS19Pro,
|
||||||
@@ -30,6 +31,5 @@ from .S19 import (
|
|||||||
BMMinerS19ProPlus,
|
BMMinerS19ProPlus,
|
||||||
BMMinerS19ProPlusHydro,
|
BMMinerS19ProPlusHydro,
|
||||||
BMMinerS19XP,
|
BMMinerS19XP,
|
||||||
BMMinerS19KPro,
|
|
||||||
)
|
)
|
||||||
from .T19 import BMMinerT19
|
from .T19 import BMMinerT19
|
||||||
|
|||||||
@@ -15,7 +15,4 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from .S21 import ePICS21, ePICS21Pro
|
from .S21 import ePICS21, ePICS21Pro
|
||||||
|
from .T21 import ePICT21
|
||||||
from .T21 import (
|
|
||||||
ePICT21,
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -597,49 +597,44 @@ class AntminerOld(CGMiner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if rpc_stats is not None:
|
if rpc_stats is not None:
|
||||||
try:
|
board_offset = -1
|
||||||
board_offset = -1
|
boards = rpc_stats["STATS"]
|
||||||
boards = rpc_stats["STATS"]
|
if len(boards) > 1:
|
||||||
if len(boards) > 1:
|
for board_num in range(1, 16, 5):
|
||||||
for board_num in range(1, 16, 5):
|
for _b_num in range(5):
|
||||||
for _b_num in range(5):
|
b = boards[1].get(f"chain_acn{board_num + _b_num}")
|
||||||
b = boards[1].get(f"chain_acn{board_num + _b_num}")
|
|
||||||
|
|
||||||
if b and not b == 0 and board_offset == -1:
|
if b and not b == 0 and board_offset == -1:
|
||||||
board_offset = board_num
|
board_offset = board_num
|
||||||
if board_offset == -1:
|
if board_offset == -1:
|
||||||
board_offset = 1
|
board_offset = 1
|
||||||
|
|
||||||
for i in range(
|
for i in range(board_offset, board_offset + self.expected_hashboards):
|
||||||
board_offset, board_offset + self.expected_hashboards
|
hashboard = HashBoard(
|
||||||
):
|
slot=i - board_offset, expected_chips=self.expected_chips
|
||||||
hashboard = HashBoard(
|
)
|
||||||
slot=i - board_offset, expected_chips=self.expected_chips
|
|
||||||
)
|
|
||||||
|
|
||||||
chip_temp = boards[1].get(f"temp{i}")
|
chip_temp = boards[1].get(f"temp{i}")
|
||||||
if chip_temp:
|
if chip_temp:
|
||||||
hashboard.chip_temp = round(chip_temp)
|
hashboard.chip_temp = round(chip_temp)
|
||||||
|
|
||||||
temp = boards[1].get(f"temp2_{i}")
|
temp = boards[1].get(f"temp2_{i}")
|
||||||
if temp:
|
if temp:
|
||||||
hashboard.temp = round(temp)
|
hashboard.temp = round(temp)
|
||||||
|
|
||||||
hashrate = boards[1].get(f"chain_rate{i}")
|
hashrate = boards[1].get(f"chain_rate{i}")
|
||||||
if hashrate:
|
if hashrate:
|
||||||
hashboard.hashrate = AlgoHashRate.SHA256(
|
hashboard.hashrate = AlgoHashRate.SHA256(
|
||||||
hashrate, HashUnit.SHA256.GH
|
float(hashrate), HashUnit.SHA256.GH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
|
|
||||||
chips = boards[1].get(f"chain_acn{i}")
|
chips = boards[1].get(f"chain_acn{i}")
|
||||||
if chips:
|
if chips:
|
||||||
hashboard.chips = chips
|
hashboard.chips = chips
|
||||||
hashboard.missing = False
|
hashboard.missing = False
|
||||||
if (not chips) or (not chips > 0):
|
if (not chips) or (not chips > 0):
|
||||||
hashboard.missing = True
|
hashboard.missing = True
|
||||||
hashboards.append(hashboard)
|
hashboards.append(hashboard)
|
||||||
except (LookupError, ValueError, TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
return hashboards
|
return hashboards
|
||||||
|
|
||||||
|
|||||||
@@ -193,7 +193,14 @@ class Auradine(StockFirmware):
|
|||||||
for key in conf.keys():
|
for key in conf.keys():
|
||||||
await self.web.send_command(command=key, **conf[key])
|
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.
|
Upgrade the firmware of the Auradine device.
|
||||||
|
|
||||||
@@ -209,7 +216,9 @@ class Auradine(StockFirmware):
|
|||||||
logging.info("Starting firmware upgrade process.")
|
logging.info("Starting firmware upgrade process.")
|
||||||
|
|
||||||
if not url and not version:
|
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:
|
if url:
|
||||||
result = await self.web.firmware_upgrade(url=url)
|
result = await self.web.firmware_upgrade(url=url)
|
||||||
@@ -220,11 +229,15 @@ class Auradine(StockFirmware):
|
|||||||
logging.info("Firmware upgrade process completed successfully.")
|
logging.info("Firmware upgrade process completed successfully.")
|
||||||
return True
|
return True
|
||||||
else:
|
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
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return False
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ from typing import List, Optional
|
|||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||||
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||||
from pyasic.miners.device.firmware import StockFirmware
|
from pyasic.miners.device.firmware import StockFirmware
|
||||||
from pyasic.rpc.bfgminer import BFGMinerRPCAPI
|
from pyasic.rpc.bfgminer import BFGMinerRPCAPI
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
|
||||||
|
|
||||||
BFGMINER_DATA_LOC = DataLocations(
|
BFGMINER_DATA_LOC = DataLocations(
|
||||||
**{
|
**{
|
||||||
@@ -263,4 +263,4 @@ class BFGMiner(StockFirmware):
|
|||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ import aiofiles
|
|||||||
from pyasic.config import MinerConfig, MiningModeConfig
|
from pyasic.config import MinerConfig, MiningModeConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||||
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
||||||
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||||
from pyasic.miners.device.firmware import StockFirmware
|
from pyasic.miners.device.firmware import StockFirmware
|
||||||
from pyasic.rpc.btminer import BTMinerRPCAPI
|
from pyasic.rpc.btminer import BTMinerRPCAPI
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
|
||||||
|
|
||||||
BTMINER_DATA_LOC = DataLocations(
|
BTMINER_DATA_LOC = DataLocations(
|
||||||
**{
|
**{
|
||||||
@@ -113,7 +113,7 @@ BTMINER_DATA_LOC = DataLocations(
|
|||||||
str(DataOptions.POOLS): DataFunction(
|
str(DataOptions.POOLS): DataFunction(
|
||||||
"_get_pools",
|
"_get_pools",
|
||||||
[RPCAPICommand("rpc_pools", "pools")],
|
[RPCAPICommand("rpc_pools", "pools")],
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -14,15 +14,15 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from typing import Optional, List
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, HashUnit
|
from pyasic.data import AlgoHashRate, HashUnit
|
||||||
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||||
from pyasic.miners.device.firmware import StockFirmware
|
from pyasic.miners.device.firmware import StockFirmware
|
||||||
from pyasic.rpc.cgminer import CGMinerRPCAPI
|
from pyasic.rpc.cgminer import CGMinerRPCAPI
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
|
||||||
|
|
||||||
CGMINER_DATA_LOC = DataLocations(
|
CGMINER_DATA_LOC = DataLocations(
|
||||||
**{
|
**{
|
||||||
|
|||||||
@@ -454,8 +454,9 @@ class ePIC(ePICFirmware):
|
|||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
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.
|
Upgrade the firmware of the ePIC miner device.
|
||||||
|
|
||||||
@@ -466,4 +467,4 @@ class ePIC(ePICFirmware):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: Whether the firmware update succeeded.
|
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 typing import List, Optional
|
||||||
|
|
||||||
|
from pyasic import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||||
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
from pyasic.device import MinerAlgo
|
from pyasic.device import MinerAlgo
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||||
@@ -41,6 +43,10 @@ ICERIVER_DATA_LOC = DataLocations(
|
|||||||
"_get_uptime",
|
"_get_uptime",
|
||||||
[WebAPICommand("web_userpanel", "userpanel")],
|
[WebAPICommand("web_userpanel", "userpanel")],
|
||||||
),
|
),
|
||||||
|
str(DataOptions.POOLS): DataFunction(
|
||||||
|
"_get_pools",
|
||||||
|
[WebAPICommand("web_userpanel", "userpanel")],
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,6 +73,11 @@ class IceRiver(StockFirmware):
|
|||||||
return False
|
return False
|
||||||
return True
|
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]:
|
async def _get_fans(self, web_userpanel: dict = None) -> List[Fan]:
|
||||||
if web_userpanel is None:
|
if web_userpanel is None:
|
||||||
try:
|
try:
|
||||||
@@ -76,7 +87,7 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
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):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -89,7 +100,9 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
try:
|
||||||
return web_userpanel["mac"].upper().replace("-", ":")
|
return (
|
||||||
|
web_userpanel["userpanel"]["data"]["mac"].upper().replace("-", ":")
|
||||||
|
)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -102,7 +115,7 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
try:
|
||||||
return web_userpanel["host"]
|
return web_userpanel["userpanel"]["data"]["host"]
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -115,9 +128,13 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
try:
|
||||||
base_unit = web_userpanel["unit"]
|
base_unit = web_userpanel["userpanel"]["data"]["unit"]
|
||||||
return AlgoHashRate.SHA256(
|
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"),
|
unit=MinerAlgo.SHA256.unit.from_str(base_unit + "H"),
|
||||||
).into(MinerAlgo.SHA256.unit.default)
|
).into(MinerAlgo.SHA256.unit.default)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
@@ -132,7 +149,7 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
try:
|
||||||
return web_userpanel["locate"]
|
return web_userpanel["userpanel"]["data"]["locate"]
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
@@ -146,7 +163,7 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
try:
|
||||||
return web_userpanel["powstate"]
|
return web_userpanel["userpanel"]["data"]["powstate"]
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -164,7 +181,7 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
try:
|
||||||
for board in web_userpanel["boards"]:
|
for board in web_userpanel["userpanel"]["data"]["boards"]:
|
||||||
idx = int(board["no"] - 1)
|
idx = int(board["no"] - 1)
|
||||||
hb_list[idx].chip_temp = round(board["outtmp"])
|
hb_list[idx].chip_temp = round(board["outtmp"])
|
||||||
hb_list[idx].temp = round(board["intmp"])
|
hb_list[idx].temp = round(board["intmp"])
|
||||||
@@ -186,7 +203,7 @@ class IceRiver(StockFirmware):
|
|||||||
|
|
||||||
if web_userpanel is not None:
|
if web_userpanel is not None:
|
||||||
try:
|
try:
|
||||||
runtime = web_userpanel["runtime"]
|
runtime = web_userpanel["userpanel"]["data"]["runtime"]
|
||||||
days, hours, minutes, seconds = runtime.split(":")
|
days, hours, minutes, seconds = runtime.split(":")
|
||||||
return (
|
return (
|
||||||
(int(days) * 24 * 60 * 60)
|
(int(days) * 24 * 60 * 60)
|
||||||
@@ -196,3 +213,36 @@ class IceRiver(StockFirmware):
|
|||||||
)
|
)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
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
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from typing import List, Optional
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ from typing import List, Optional
|
|||||||
from pyasic import MinerConfig
|
from pyasic import MinerConfig
|
||||||
from pyasic.config import MiningModeConfig
|
from pyasic.config import MiningModeConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
||||||
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||||
from pyasic.miners.device.firmware import MaraFirmware
|
from pyasic.miners.device.firmware import MaraFirmware
|
||||||
from pyasic.misc import merge_dicts
|
from pyasic.misc import merge_dicts
|
||||||
from pyasic.rpc.marathon import MaraRPCAPI
|
from pyasic.rpc.marathon import MaraRPCAPI
|
||||||
from pyasic.web.marathon import MaraWebAPI
|
from pyasic.web.marathon import MaraWebAPI
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
|
||||||
|
|
||||||
MARA_DATA_LOC = DataLocations(
|
MARA_DATA_LOC = DataLocations(
|
||||||
**{
|
**{
|
||||||
@@ -319,10 +319,13 @@ class MaraMiner(MaraFirmware):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
active_pool_index = None
|
active_pool_index = None
|
||||||
highest_priority = float('inf')
|
highest_priority = float("inf")
|
||||||
|
|
||||||
for pool_info in web_pools:
|
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"]
|
highest_priority = pool_info.get["priority"]
|
||||||
active_pool_index = pool_info["index"]
|
active_pool_index = pool_info["index"]
|
||||||
|
|
||||||
|
|||||||
@@ -560,7 +560,14 @@ class BaseMiner(MinerProtocol):
|
|||||||
if self._ssh_cls is not None:
|
if self._ssh_cls is not None:
|
||||||
self.ssh = self._ssh_cls(ip)
|
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.
|
"""Upgrade the firmware of the miner.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@@ -574,4 +581,5 @@ class BaseMiner(MinerProtocol):
|
|||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
AnyMiner = TypeVar("AnyMiner", bound=BaseMiner)
|
AnyMiner = TypeVar("AnyMiner", bound=BaseMiner)
|
||||||
|
|||||||
@@ -14,7 +14,4 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from .blockminer import (
|
from .blockminer import ePICBlockMiner520i, ePICBlockMiner720i
|
||||||
ePICBlockMiner520i,
|
|
||||||
ePICBlockMiner720i,
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -43,4 +43,4 @@ class LuxOSFirmware(BaseMiner):
|
|||||||
|
|
||||||
|
|
||||||
class MaraFirmware(BaseMiner):
|
class MaraFirmware(BaseMiner):
|
||||||
firmware = MinerFirmware.MARATHON
|
firmware = MinerFirmware.MARATHON
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ class A11MX(InnosiliconMake):
|
|||||||
raw_model = MinerModel.INNOSILICON.A11MX
|
raw_model = MinerModel.INNOSILICON.A11MX
|
||||||
|
|
||||||
expected_hashboards = 4
|
expected_hashboards = 4
|
||||||
|
expected_chips = 8
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import hashlib
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Literal, Union
|
|
||||||
import struct
|
import struct
|
||||||
|
from typing import Literal, Union
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||||
|
|||||||
@@ -757,4 +757,4 @@ class LUXMinerRPCAPI(BaseMinerRPCAPI):
|
|||||||
Returns:
|
Returns:
|
||||||
The response from the miner after sending the 'updaterun' command.
|
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 asyncio
|
||||||
import json
|
import json
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
import httpx
|
import httpx
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from pyasic import settings
|
from pyasic import settings
|
||||||
from pyasic.web.base import BaseWebAPI
|
from pyasic.web.base import BaseWebAPI
|
||||||
@@ -414,10 +415,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
parameters = {
|
parameters = {
|
||||||
"file": (file.name, file_content, "application/octet-stream"),
|
"file": (file.name, file_content, "application/octet-stream"),
|
||||||
"filename": file.name,
|
"filename": file.name,
|
||||||
"keep_settings": keep_settings
|
"keep_settings": keep_settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
return await self.send_command(
|
return await self.send_command(command="upgrade", **parameters)
|
||||||
command="upgrade",
|
|
||||||
**parameters
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -4,17 +4,12 @@
|
|||||||
# This file has been @generated
|
# This file has been @generated
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import (
|
from typing import TYPE_CHECKING, Dict, Optional
|
||||||
TYPE_CHECKING,
|
|
||||||
Dict,
|
|
||||||
Optional,
|
|
||||||
)
|
|
||||||
|
|
||||||
import betterproto
|
import betterproto
|
||||||
import grpclib
|
import grpclib
|
||||||
from betterproto.grpc.grpclib_server import ServiceBase
|
from betterproto.grpc.grpclib_server import ServiceBase
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import grpclib.server
|
import grpclib.server
|
||||||
from betterproto.grpc.grpclib_client import MetadataLike
|
from betterproto.grpc.grpclib_client import MetadataLike
|
||||||
|
|||||||
@@ -5,19 +5,12 @@
|
|||||||
import warnings
|
import warnings
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import (
|
from typing import TYPE_CHECKING, AsyncIterator, Dict, List, Optional
|
||||||
TYPE_CHECKING,
|
|
||||||
AsyncIterator,
|
|
||||||
Dict,
|
|
||||||
List,
|
|
||||||
Optional,
|
|
||||||
)
|
|
||||||
|
|
||||||
import betterproto
|
import betterproto
|
||||||
import grpclib
|
import grpclib
|
||||||
from betterproto.grpc.grpclib_server import ServiceBase
|
from betterproto.grpc.grpclib_server import ServiceBase
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import grpclib.server
|
import grpclib.server
|
||||||
from betterproto.grpc.grpclib_client import MetadataLike
|
from betterproto.grpc.grpclib_client import MetadataLike
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pyasic"
|
name = "pyasic"
|
||||||
version = "0.61.7"
|
version = "0.61.15"
|
||||||
description = "A simplified and standardized interface for Bitcoin ASICs."
|
description = "A simplified and standardized interface for Bitcoin ASICs."
|
||||||
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
||||||
repository = "https://github.com/UpstreamData/pyasic"
|
repository = "https://github.com/UpstreamData/pyasic"
|
||||||
@@ -15,8 +15,8 @@ passlib = ">=1.7.4"
|
|||||||
pyaml = ">=23.12.0"
|
pyaml = ">=23.12.0"
|
||||||
tomli = { version = ">=2.0.1", python = "<3.11" }
|
tomli = { version = ">=2.0.1", python = "<3.11" }
|
||||||
tomli-w = "^1.0.0"
|
tomli-w = "^1.0.0"
|
||||||
betterproto = "2.0.0b7"
|
|
||||||
aiofiles = ">=23.2.1"
|
aiofiles = ">=23.2.1"
|
||||||
|
betterproto = "2.0.0b7"
|
||||||
|
|
||||||
[tool.poetry.group.dev]
|
[tool.poetry.group.dev]
|
||||||
optional = true
|
optional = true
|
||||||
|
|||||||
Reference in New Issue
Block a user