Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d018724aa4 | ||
|
|
5b97bed704 | ||
|
|
55786b154d | ||
|
|
6ab9681dec | ||
|
|
89641c6316 | ||
|
|
136ff6a688 | ||
|
|
d918d93f4a | ||
|
|
8046c532a6 | ||
|
|
92820a362d | ||
|
|
9fd90031a9 | ||
|
|
2f2223a112 | ||
|
|
50e6cf9dfd | ||
|
|
1b5e3093e6 | ||
|
|
9e3578b4a2 | ||
|
|
a3087e1a96 | ||
|
|
4b16ea2ca2 | ||
|
|
5dd361c4ef | ||
|
|
098112742c | ||
|
|
cd31e0743e | ||
|
|
1a7d0bf7cc | ||
|
|
41b5ebf0f0 | ||
|
|
5436bede29 | ||
|
|
c01b3958dc | ||
|
|
c16367285f | ||
|
|
17eae253e6 | ||
|
|
ab30988614 | ||
|
|
9b8e547f86 | ||
|
|
3b8cbb9ff1 | ||
|
|
d39d278296 | ||
|
|
ea8b922367 | ||
|
|
0d1c8d80e0 | ||
|
|
494d25da97 |
6
.github/workflows/python-publish.yml
vendored
6
.github/workflows/python-publish.yml
vendored
@@ -13,10 +13,10 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4.2.2
|
||||||
- name: Publish GH release
|
- name: Publish GH release
|
||||||
uses: softprops/action-gh-release@v0.1.14
|
uses: softprops/action-gh-release@v2.1.0
|
||||||
- name: Build using poetry and publish to PyPi
|
- name: Build using poetry and publish to PyPi
|
||||||
uses: JRubics/poetry-publish@v1.11
|
uses: JRubics/poetry-publish@v2.0
|
||||||
with:
|
with:
|
||||||
pypi_token: ${{ secrets.PYPI_API_KEY }}
|
pypi_token: ${{ secrets.PYPI_API_KEY }}
|
||||||
|
|||||||
@@ -302,6 +302,13 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19k Pro (VNish)
|
||||||
|
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19kPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## T19 (VNish)
|
## T19 (VNish)
|
||||||
::: pyasic.miners.antminer.vnish.X19.T19.VNishT19
|
::: pyasic.miners.antminer.vnish.X19.T19.VNishT19
|
||||||
handler: python
|
handler: python
|
||||||
@@ -358,13 +365,20 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j Pro (Stock)
|
## S19j Pro (Hive)
|
||||||
::: pyasic.miners.antminer.hiveon.X19.S19.HiveonS19jPro
|
::: pyasic.miners.antminer.hiveon.X19.S19.HiveonS19jPro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 (Hive)
|
||||||
|
::: pyasic.miners.antminer.hiveon.X19.S19.HiveonS19
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## S19 (LuxOS)
|
## S19 (LuxOS)
|
||||||
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19
|
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19
|
||||||
handler: python
|
handler: python
|
||||||
|
|||||||
@@ -43,6 +43,13 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## L9 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X9.L9.BMMinerL9
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## S9 (BOS+)
|
## S9 (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
|
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
|
||||||
handler: python
|
handler: python
|
||||||
@@ -50,7 +57,7 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T9 (Stock)
|
## T9 (Hive)
|
||||||
::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9
|
::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A11X Models
|
## A11X Models
|
||||||
|
|
||||||
|
## Avalon 1126 Pro (Stock)
|
||||||
|
::: pyasic.miners.avalonminer.cgminer.A11X.A1126.CGMinerAvalon1126Pro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## Avalon 1166 Pro (Stock)
|
## Avalon 1166 Pro (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A11X.A1166.CGMinerAvalon1166Pro
|
::: pyasic.miners.avalonminer.cgminer.A11X.A1166.CGMinerAvalon1166Pro
|
||||||
handler: python
|
handler: python
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ details {
|
|||||||
<li><a href="../antminer/X9#s9i-stock">S9i (Stock)</a></li>
|
<li><a href="../antminer/X9#s9i-stock">S9i (Stock)</a></li>
|
||||||
<li><a href="../antminer/X9#s9j-stock">S9j (Stock)</a></li>
|
<li><a href="../antminer/X9#s9j-stock">S9j (Stock)</a></li>
|
||||||
<li><a href="../antminer/X9#t9-stock">T9 (Stock)</a></li>
|
<li><a href="../antminer/X9#t9-stock">T9 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X9#l9-stock">L9 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
@@ -377,6 +378,7 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>A11X Series:</summary>
|
<summary>A11X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><a href="../avalonminer/A11X#avalon-1126-pro-stock">Avalon 1126 Pro (Stock)</a></li>
|
||||||
<li><a href="../avalonminer/A11X#avalon-1166-pro-stock">Avalon 1166 Pro (Stock)</a></li>
|
<li><a href="../avalonminer/A11X#avalon-1166-pro-stock">Avalon 1166 Pro (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
@@ -531,6 +533,7 @@ details {
|
|||||||
<li><a href="../antminer/X19#s19a-vnish">S19a (VNish)</a></li>
|
<li><a href="../antminer/X19#s19a-vnish">S19a (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#s19a-pro-vnish">S19a Pro (VNish)</a></li>
|
<li><a href="../antminer/X19#s19a-pro-vnish">S19a Pro (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#s19-pro-hydro-vnish">S19 Pro Hydro (VNish)</a></li>
|
<li><a href="../antminer/X19#s19-pro-hydro-vnish">S19 Pro Hydro (VNish)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19k-pro-vnish">S19k Pro (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#t19-vnish">T19 (VNish)</a></li>
|
<li><a href="../antminer/X19#t19-vnish">T19 (VNish)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
@@ -580,13 +583,14 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>X9 Series:</summary>
|
<summary>X9 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X9#t9-stock">T9 (Stock)</a></li>
|
<li><a href="../antminer/X9#t9-hive">T9 (Hive)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X19 Series:</summary>
|
<summary>X19 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X19#s19j-pro-stock">S19j Pro (Stock)</a></li>
|
<li><a href="../antminer/X19#s19j-pro-hive">S19j Pro (Hive)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-hive">S19 (Hive)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class MiningPreset(MinerConfigValue):
|
|||||||
hashrate = None
|
hashrate = None
|
||||||
else:
|
else:
|
||||||
power = hr_power_split[0].replace("watt", "").strip()
|
power = hr_power_split[0].replace("watt", "").strip()
|
||||||
hashrate = hr_power_split[1].replace("TH", "").strip()
|
hashrate = hr_power_split[1].replace("TH", "").replace(" LC", "").strip()
|
||||||
tuned = web_preset["status"] == "tuned"
|
tuned = web_preset["status"] == "tuned"
|
||||||
modded_psu = web_preset["modded_psu_required"]
|
modded_psu = web_preset["modded_psu_required"]
|
||||||
return cls(
|
return cls(
|
||||||
|
|||||||
@@ -13,19 +13,20 @@
|
|||||||
# 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. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any, List, Union
|
from typing import Any, List, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, computed_field, field_serializer
|
from pydantic import BaseModel, Field, computed_field
|
||||||
|
|
||||||
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, Scheme
|
from pyasic.data.pools import PoolMetrics, Scheme
|
||||||
from pyasic.device.algorithm.hashrate import AlgoHashRateType
|
from pyasic.device.algorithm.hashrate import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.base import GenericHashrate
|
||||||
|
|
||||||
|
from ..device.algorithm.hashrate.unit.base import GenericUnit
|
||||||
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
|
||||||
@@ -96,7 +97,7 @@ class MinerData(BaseModel):
|
|||||||
expected_fans: int | None = None
|
expected_fans: int | None = None
|
||||||
|
|
||||||
# temperature
|
# temperature
|
||||||
env_temp: int | None = None
|
env_temp: float | None = None
|
||||||
|
|
||||||
# power
|
# power
|
||||||
wattage: int | None = None
|
wattage: int | None = None
|
||||||
@@ -135,9 +136,6 @@ class MinerData(BaseModel):
|
|||||||
def fields(cls):
|
def fields(cls):
|
||||||
return list(cls.model_fields.keys())
|
return list(cls.model_fields.keys())
|
||||||
|
|
||||||
def __post_init__(self):
|
|
||||||
self.raw_datetime = datetime.now(timezone.utc).astimezone()
|
|
||||||
|
|
||||||
def get(self, __key: str, default: Any = None):
|
def get(self, __key: str, default: Any = None):
|
||||||
try:
|
try:
|
||||||
val = self.__getitem__(__key)
|
val = self.__getitem__(__key)
|
||||||
@@ -198,35 +196,23 @@ class MinerData(BaseModel):
|
|||||||
|
|
||||||
@computed_field # type: ignore[misc]
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def hashrate(self) -> AlgoHashRateType:
|
def hashrate(self) -> AlgoHashRateType | None:
|
||||||
if len(self.hashboards) > 0:
|
if len(self.hashboards) > 0:
|
||||||
hr_data = []
|
hr_data = []
|
||||||
for item in self.hashboards:
|
for item in self.hashboards:
|
||||||
if item.hashrate is not None:
|
if item.hashrate is not None:
|
||||||
hr_data.append(item.hashrate)
|
hr_data.append(item.hashrate)
|
||||||
if len(hr_data) > 0:
|
if len(hr_data) > 0:
|
||||||
return sum(hr_data, start=type(hr_data[0])(rate=0))
|
return sum(hr_data, start=self.device_info.algo.hashrate(rate=0))
|
||||||
return self.raw_hashrate
|
return self.raw_hashrate
|
||||||
|
|
||||||
@field_serializer("hashrate")
|
|
||||||
def serialize_hashrate(self, hashrate: AlgoHashRateType | None) -> float:
|
|
||||||
if hashrate is not None:
|
|
||||||
return float(hashrate)
|
|
||||||
|
|
||||||
@field_serializer("expected_hashrate")
|
|
||||||
def serialize_expected_hashrate(
|
|
||||||
self, expected_hashrate: AlgoHashRateType | None, _info
|
|
||||||
) -> float:
|
|
||||||
if expected_hashrate is not None:
|
|
||||||
return float(expected_hashrate)
|
|
||||||
|
|
||||||
@hashrate.setter
|
@hashrate.setter
|
||||||
def hashrate(self, val):
|
def hashrate(self, val):
|
||||||
self.raw_hashrate = val
|
self.raw_hashrate = val
|
||||||
|
|
||||||
@computed_field # type: ignore[misc]
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def wattage_limit(self) -> int:
|
def wattage_limit(self) -> int | None:
|
||||||
if self.config is not None:
|
if self.config is not None:
|
||||||
if isinstance(self.config.mining_mode, MiningModePowerTune):
|
if isinstance(self.config.mining_mode, MiningModePowerTune):
|
||||||
return self.config.mining_mode.power
|
return self.config.mining_mode.power
|
||||||
|
|||||||
@@ -51,11 +51,6 @@ class HashBoard(BaseModel):
|
|||||||
active: bool | None = None
|
active: bool | None = None
|
||||||
voltage: float | None = None
|
voltage: float | None = None
|
||||||
|
|
||||||
@field_serializer("hashrate")
|
|
||||||
def serialize_hashrate(self, hashrate: AlgoHashRateType | None) -> float:
|
|
||||||
if hashrate is not None:
|
|
||||||
return float(hashrate)
|
|
||||||
|
|
||||||
def get(self, __key: str, default: Any = None):
|
def get(self, __key: str, default: Any = None):
|
||||||
try:
|
try:
|
||||||
val = self.__getitem__(__key)
|
val = self.__getitem__(__key)
|
||||||
|
|||||||
@@ -1,19 +1,42 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, field_serializer
|
||||||
from typing_extensions import Self
|
from typing_extensions import Self
|
||||||
|
|
||||||
from .unit.base import AlgoHashRateUnitType
|
from .unit.base import AlgoHashRateUnitType, GenericUnit
|
||||||
|
|
||||||
|
|
||||||
class AlgoHashRateType(BaseModel, ABC):
|
class AlgoHashRateType(BaseModel, ABC):
|
||||||
unit: AlgoHashRateUnitType
|
unit: AlgoHashRateUnitType
|
||||||
rate: float
|
rate: float
|
||||||
|
|
||||||
|
@field_serializer("unit")
|
||||||
|
def serialize_unit(self, unit: AlgoHashRateUnitType):
|
||||||
|
return unit.model_dump()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def into(self, other: "AlgoHashRateUnitType"):
|
def into(self, other: "AlgoHashRateUnitType"):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def auto_unit(self):
|
||||||
|
if 1 < self.rate // int(self.unit.H) < 1000:
|
||||||
|
return self.into(self.unit.H)
|
||||||
|
if 1 < self.rate // int(self.unit.MH) < 1000:
|
||||||
|
return self.into(self.unit.MH)
|
||||||
|
if 1 < self.rate // int(self.unit.GH) < 1000:
|
||||||
|
return self.into(self.unit.GH)
|
||||||
|
if 1 < self.rate // int(self.unit.TH) < 1000:
|
||||||
|
return self.into(self.unit.TH)
|
||||||
|
if 1 < self.rate // int(self.unit.PH) < 1000:
|
||||||
|
return self.into(self.unit.PH)
|
||||||
|
if 1 < self.rate // int(self.unit.EH) < 1000:
|
||||||
|
return self.into(self.unit.EH)
|
||||||
|
if 1 < self.rate // int(self.unit.ZH) < 1000:
|
||||||
|
return self.into(self.unit.ZH)
|
||||||
|
return self
|
||||||
|
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
return float(self.rate)
|
return float(self.rate)
|
||||||
|
|
||||||
@@ -27,36 +50,46 @@ class AlgoHashRateType(BaseModel, ABC):
|
|||||||
return round(self.rate, n)
|
return round(self.rate, n)
|
||||||
|
|
||||||
def __add__(self, other: Self | int | float) -> Self:
|
def __add__(self, other: Self | int | float) -> Self:
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, AlgoHashRateType):
|
||||||
return self.__class__(
|
return self.__class__(
|
||||||
rate=self.rate + other.into(self.unit).rate, unit=self.unit
|
rate=self.rate + other.into(self.unit).rate, unit=self.unit
|
||||||
)
|
)
|
||||||
return self.__class__(rate=self.rate + other, unit=self.unit)
|
return self.__class__(rate=self.rate + other, unit=self.unit)
|
||||||
|
|
||||||
def __sub__(self, other: Self | int | float) -> Self:
|
def __sub__(self, other: Self | int | float) -> Self:
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, AlgoHashRateType):
|
||||||
return self.__class__(
|
return self.__class__(
|
||||||
rate=self.rate - other.into(self.unit).rate, unit=self.unit
|
rate=self.rate - other.into(self.unit).rate, unit=self.unit
|
||||||
)
|
)
|
||||||
return self.__class__(rate=self.rate - other, unit=self.unit)
|
return self.__class__(rate=self.rate - other, unit=self.unit)
|
||||||
|
|
||||||
def __truediv__(self, other: Self | int | float) -> Self:
|
def __truediv__(self, other: Self | int | float) -> Self:
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, AlgoHashRateType):
|
||||||
return self.__class__(
|
return self.__class__(
|
||||||
rate=self.rate / other.into(self.unit).rate, unit=self.unit
|
rate=self.rate / other.into(self.unit).rate, unit=self.unit
|
||||||
)
|
)
|
||||||
return self.__class__(rate=self.rate / other, unit=self.unit)
|
return self.__class__(rate=self.rate / other, unit=self.unit)
|
||||||
|
|
||||||
def __floordiv__(self, other: Self | int | float) -> Self:
|
def __floordiv__(self, other: Self | int | float) -> Self:
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, AlgoHashRateType):
|
||||||
return self.__class__(
|
return self.__class__(
|
||||||
rate=self.rate // other.into(self.unit).rate, unit=self.unit
|
rate=self.rate // other.into(self.unit).rate, unit=self.unit
|
||||||
)
|
)
|
||||||
return self.__class__(rate=self.rate // other, unit=self.unit)
|
return self.__class__(rate=self.rate // other, unit=self.unit)
|
||||||
|
|
||||||
def __mul__(self, other: Self | int | float) -> Self:
|
def __mul__(self, other: Self | int | float) -> Self:
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, AlgoHashRateType):
|
||||||
return self.__class__(
|
return self.__class__(
|
||||||
rate=self.rate * other.into(self.unit).rate, unit=self.unit
|
rate=self.rate * other.into(self.unit).rate, unit=self.unit
|
||||||
)
|
)
|
||||||
return self.__class__(rate=self.rate * other, unit=self.unit)
|
return self.__class__(rate=self.rate * other, unit=self.unit)
|
||||||
|
|
||||||
|
|
||||||
|
class GenericHashrate(AlgoHashRateType):
|
||||||
|
rate: float = 0
|
||||||
|
unit: GenericUnit = GenericUnit.H
|
||||||
|
|
||||||
|
def into(self, other: GenericUnit):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
|
|||||||
@@ -53,3 +53,19 @@ class AlgoHashRateUnitType(IntEnum):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
|
def model_dump(self):
|
||||||
|
return {"value": self.value, "suffix": str(self)}
|
||||||
|
|
||||||
|
|
||||||
|
class GenericUnit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = H
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from enum import IntEnum
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
class ScryptUnit(IntEnum):
|
class ScryptUnit(AlgoHashRateUnitType):
|
||||||
H = 1
|
H = 1
|
||||||
KH = int(H) * 1000
|
KH = int(H) * 1000
|
||||||
MH = int(KH) * 1000
|
MH = int(KH) * 1000
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class AntminerModels(MinerModelType):
|
|||||||
S9j = "S9j"
|
S9j = "S9j"
|
||||||
T9 = "T9"
|
T9 = "T9"
|
||||||
D9 = "D9"
|
D9 = "D9"
|
||||||
|
L9 = "L9"
|
||||||
Z15 = "Z15"
|
Z15 = "Z15"
|
||||||
Z15Pro = "Z15 Pro"
|
Z15Pro = "Z15 Pro"
|
||||||
S17 = "S17"
|
S17 = "S17"
|
||||||
@@ -295,6 +296,7 @@ class AvalonminerModels(MinerModelType):
|
|||||||
Avalon1047 = "Avalon 1047"
|
Avalon1047 = "Avalon 1047"
|
||||||
Avalon1066 = "Avalon 1066"
|
Avalon1066 = "Avalon 1066"
|
||||||
Avalon1166Pro = "Avalon 1166 Pro"
|
Avalon1166Pro = "Avalon 1166 Pro"
|
||||||
|
Avalon1126Pro = "Avalon 1126 Pro"
|
||||||
Avalon1246 = "Avalon 1246"
|
Avalon1246 = "Avalon 1246"
|
||||||
AvalonNano3 = "Avalon Nano 3"
|
AvalonNano3 = "Avalon Nano 3"
|
||||||
|
|
||||||
|
|||||||
22
pyasic/miners/antminer/bmminer/X9/L9.py
Normal file
22
pyasic/miners/antminer/bmminer/X9/L9.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright 2022 Upstream Data Inc -
|
||||||
|
# -
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||||
|
# you may not use this file except in compliance with the License. -
|
||||||
|
# You may obtain a copy of the License at -
|
||||||
|
# -
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||||
|
# -
|
||||||
|
# Unless required by applicable law or agreed to in writing, software -
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||||
|
# See the License for the specific language governing permissions and -
|
||||||
|
# limitations under the License. -
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from pyasic.miners.backends import AntminerModern
|
||||||
|
from pyasic.miners.device.models import L9
|
||||||
|
|
||||||
|
|
||||||
|
class BMMinerL9(AntminerModern, L9):
|
||||||
|
pass
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
|
|
||||||
from .D9 import BMMinerD9
|
from .D9 import BMMinerD9
|
||||||
from .E9 import BMMinerE9Pro
|
from .E9 import BMMinerE9Pro
|
||||||
|
from .L9 import BMMinerL9
|
||||||
from .S9 import BMMinerS9, BMMinerS9i, BMMinerS9j
|
from .S9 import BMMinerS9, BMMinerS9i, BMMinerS9j
|
||||||
from .T9 import BMMinerT9
|
from .T9 import BMMinerT9
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from pyasic.miners.device.models import (
|
|||||||
S19aPro,
|
S19aPro,
|
||||||
S19j,
|
S19j,
|
||||||
S19jPro,
|
S19jPro,
|
||||||
|
S19kPro,
|
||||||
S19NoPIC,
|
S19NoPIC,
|
||||||
S19Pro,
|
S19Pro,
|
||||||
S19ProHydro,
|
S19ProHydro,
|
||||||
@@ -62,3 +63,7 @@ class VNishS19jPro(VNish, S19jPro):
|
|||||||
|
|
||||||
class VNishS19ProHydro(VNish, S19ProHydro):
|
class VNishS19ProHydro(VNish, S19ProHydro):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class VNishS19kPro(VNish, S19kPro):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ from .S19 import (
|
|||||||
VNishS19aPro,
|
VNishS19aPro,
|
||||||
VNishS19j,
|
VNishS19j,
|
||||||
VNishS19jPro,
|
VNishS19jPro,
|
||||||
|
VNishS19kPro,
|
||||||
VNishS19NoPIC,
|
VNishS19NoPIC,
|
||||||
VNishS19Pro,
|
VNishS19Pro,
|
||||||
VNishS19ProHydro,
|
VNishS19ProHydro,
|
||||||
|
|||||||
22
pyasic/miners/avalonminer/cgminer/A11X/A1126.py
Normal file
22
pyasic/miners/avalonminer/cgminer/A11X/A1126.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright 2022 Upstream Data Inc -
|
||||||
|
# -
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||||
|
# you may not use this file except in compliance with the License. -
|
||||||
|
# You may obtain a copy of the License at -
|
||||||
|
# -
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||||
|
# -
|
||||||
|
# Unless required by applicable law or agreed to in writing, software -
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||||
|
# See the License for the specific language governing permissions and -
|
||||||
|
# limitations under the License. -
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from pyasic.miners.backends import AvalonMiner
|
||||||
|
from pyasic.miners.device.models import Avalon1126Pro
|
||||||
|
|
||||||
|
|
||||||
|
class CGMinerAvalon1126Pro(AvalonMiner, Avalon1126Pro):
|
||||||
|
pass
|
||||||
@@ -14,4 +14,5 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from .A1126 import CGMinerAvalon1126Pro
|
||||||
from .A1166 import CGMinerAvalon1166Pro
|
from .A1166 import CGMinerAvalon1166Pro
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pyasic import MinerConfig
|
from pyasic import MinerConfig
|
||||||
@@ -96,6 +97,7 @@ class VNish(VNishFirmware, BMMiner):
|
|||||||
|
|
||||||
supports_shutdown = True
|
supports_shutdown = True
|
||||||
supports_presets = True
|
supports_presets = True
|
||||||
|
supports_autotuning = True
|
||||||
|
|
||||||
data_locations = VNISH_DATA_LOC
|
data_locations = VNISH_DATA_LOC
|
||||||
|
|
||||||
@@ -272,3 +274,27 @@ class VNish(VNishFirmware, BMMiner):
|
|||||||
return self.config
|
return self.config
|
||||||
self.config = MinerConfig.from_vnish(web_settings, web_presets)
|
self.config = MinerConfig.from_vnish(web_settings, web_presets)
|
||||||
return self.config
|
return self.config
|
||||||
|
|
||||||
|
async def set_power_limit(self, wattage: int) -> bool:
|
||||||
|
config = await self.get_config()
|
||||||
|
valid_presets = [
|
||||||
|
preset.power
|
||||||
|
for preset in config.mining_mode.available_presets
|
||||||
|
if preset.tuned and preset.power <= wattage
|
||||||
|
]
|
||||||
|
new_wattage = max(valid_presets)
|
||||||
|
|
||||||
|
# Set power to highest preset <= wattage
|
||||||
|
try:
|
||||||
|
await self.web.set_power_limit(new_wattage)
|
||||||
|
updated_settings = await self.web.settings()
|
||||||
|
except APIError:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f"{self} - Failed to set power limit: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if int(updated_settings["miner"]["overclock"]["preset"]) == new_wattage:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|||||||
27
pyasic/miners/device/models/antminer/X9/L9.py
Normal file
27
pyasic/miners/device/models/antminer/X9/L9.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright 2022 Upstream Data Inc -
|
||||||
|
# -
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||||
|
# you may not use this file except in compliance with the License. -
|
||||||
|
# You may obtain a copy of the License at -
|
||||||
|
# -
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||||
|
# -
|
||||||
|
# Unless required by applicable law or agreed to in writing, software -
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||||
|
# See the License for the specific language governing permissions and -
|
||||||
|
# limitations under the License. -
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
from pyasic.device.algorithm import MinerAlgo
|
||||||
|
from pyasic.device.models import MinerModel
|
||||||
|
from pyasic.miners.device.makes import AntMinerMake
|
||||||
|
|
||||||
|
|
||||||
|
class L9(AntMinerMake):
|
||||||
|
raw_model = MinerModel.ANTMINER.L9
|
||||||
|
|
||||||
|
expected_chips = 110
|
||||||
|
expected_hashboards = 3
|
||||||
|
expected_fans = 4
|
||||||
|
algo = MinerAlgo.SCRYPT
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
|
|
||||||
from .D9 import D9
|
from .D9 import D9
|
||||||
from .E9 import E9Pro
|
from .E9 import E9Pro
|
||||||
|
from .L9 import L9
|
||||||
from .S9 import S9, S9i, S9j
|
from .S9 import S9, S9i, S9j
|
||||||
from .T9 import T9
|
from .T9 import T9
|
||||||
|
|||||||
27
pyasic/miners/device/models/avalonminer/A11X/A1126.py
Normal file
27
pyasic/miners/device/models/avalonminer/A11X/A1126.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Copyright 2022 Upstream Data Inc -
|
||||||
|
# -
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||||
|
# you may not use this file except in compliance with the License. -
|
||||||
|
# You may obtain a copy of the License at -
|
||||||
|
# -
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||||
|
# -
|
||||||
|
# Unless required by applicable law or agreed to in writing, software -
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||||
|
# See the License for the specific language governing permissions and -
|
||||||
|
# limitations under the License. -
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
from pyasic.device.algorithm import MinerAlgo
|
||||||
|
from pyasic.device.models import MinerModel
|
||||||
|
from pyasic.miners.device.makes import AvalonMinerMake
|
||||||
|
|
||||||
|
|
||||||
|
class Avalon1126Pro(AvalonMinerMake):
|
||||||
|
raw_model = MinerModel.AVALONMINER.Avalon1126Pro
|
||||||
|
|
||||||
|
expected_chips = 120
|
||||||
|
expected_fans = 4
|
||||||
|
expected_hashboards = 3
|
||||||
|
algo = MinerAlgo.SHA256
|
||||||
@@ -15,4 +15,5 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
from .A1126 import Avalon1126Pro
|
||||||
from .A1166 import Avalon1166Pro
|
from .A1166 import Avalon1166Pro
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ MINER_CLASSES = {
|
|||||||
"ANTMINER S9I": BMMinerS9i,
|
"ANTMINER S9I": BMMinerS9i,
|
||||||
"ANTMINER S9J": BMMinerS9j,
|
"ANTMINER S9J": BMMinerS9j,
|
||||||
"ANTMINER T9": BMMinerT9,
|
"ANTMINER T9": BMMinerT9,
|
||||||
|
"ANTMINER L9": BMMinerL9,
|
||||||
"ANTMINER Z15": CGMinerZ15,
|
"ANTMINER Z15": CGMinerZ15,
|
||||||
"ANTMINER Z15 PRO": BMMinerZ15Pro,
|
"ANTMINER Z15 PRO": BMMinerZ15Pro,
|
||||||
"ANTMINER S17": BMMinerS17,
|
"ANTMINER S17": BMMinerS17,
|
||||||
@@ -339,6 +340,7 @@ MINER_CLASSES = {
|
|||||||
"AVALONMINER 1026": CGMinerAvalon1026,
|
"AVALONMINER 1026": CGMinerAvalon1026,
|
||||||
"AVALONMINER 1047": CGMinerAvalon1047,
|
"AVALONMINER 1047": CGMinerAvalon1047,
|
||||||
"AVALONMINER 1066": CGMinerAvalon1066,
|
"AVALONMINER 1066": CGMinerAvalon1066,
|
||||||
|
"AVALONMINER 1126PRO": CGMinerAvalon1126Pro,
|
||||||
"AVALONMINER 1166PRO": CGMinerAvalon1166Pro,
|
"AVALONMINER 1166PRO": CGMinerAvalon1166Pro,
|
||||||
"AVALONMINER 1246": CGMinerAvalon1246,
|
"AVALONMINER 1246": CGMinerAvalon1246,
|
||||||
"AVALONMINER NANO3": CGMinerAvalonNano3,
|
"AVALONMINER NANO3": CGMinerAvalonNano3,
|
||||||
@@ -405,6 +407,7 @@ MINER_CLASSES = {
|
|||||||
"ANTMINER S19A": VNishS19a,
|
"ANTMINER S19A": VNishS19a,
|
||||||
"ANTMINER S19A PRO": VNishS19aPro,
|
"ANTMINER S19A PRO": VNishS19aPro,
|
||||||
"ANTMINER S19 PRO HYD.": VNishS19ProHydro,
|
"ANTMINER S19 PRO HYD.": VNishS19ProHydro,
|
||||||
|
"ANTMINER S19K PRO": VNishS19kPro,
|
||||||
"ANTMINER T19": VNishT19,
|
"ANTMINER T19": VNishT19,
|
||||||
"ANTMINER S21": VNishS21,
|
"ANTMINER S21": VNishS21,
|
||||||
},
|
},
|
||||||
@@ -427,6 +430,7 @@ MINER_CLASSES = {
|
|||||||
None: HiveonModern,
|
None: HiveonModern,
|
||||||
"ANTMINER T9": HiveonT9,
|
"ANTMINER T9": HiveonT9,
|
||||||
"ANTMINER S19JPRO": HiveonS19jPro,
|
"ANTMINER S19JPRO": HiveonS19jPro,
|
||||||
|
"ANTMINER S19": HiveonS19,
|
||||||
},
|
},
|
||||||
MinerTypes.LUX_OS: {
|
MinerTypes.LUX_OS: {
|
||||||
None: LUXMiner,
|
None: LUXMiner,
|
||||||
@@ -873,7 +877,7 @@ class MinerFactory:
|
|||||||
if miner_type in MINER_CLASSES:
|
if miner_type in MINER_CLASSES:
|
||||||
if miner_model is not None:
|
if miner_model is not None:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
f"Partially supported miner found: {miner_model}, please open an issue with miner data "
|
f"Partially supported miner found: {miner_model}, type: {miner_type}, please open an issue with miner data "
|
||||||
f"and this model on GitHub (https://github.com/UpstreamData/pyasic/issues)."
|
f"and this model on GitHub (https://github.com/UpstreamData/pyasic/issues)."
|
||||||
)
|
)
|
||||||
return MINER_CLASSES[miner_type][None](ip)
|
return MINER_CLASSES[miner_type][None](ip)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ _settings = { # defaults
|
|||||||
"default_goldshell_web_password": "123456789",
|
"default_goldshell_web_password": "123456789",
|
||||||
"default_auradine_web_password": "admin",
|
"default_auradine_web_password": "admin",
|
||||||
"default_epic_web_password": "letmein",
|
"default_epic_web_password": "letmein",
|
||||||
"default_hive_web_password": "admin",
|
"default_hive_web_password": "root",
|
||||||
"default_iceriver_web_password": "12345678",
|
"default_iceriver_web_password": "12345678",
|
||||||
"default_antminer_ssh_password": "miner",
|
"default_antminer_ssh_password": "miner",
|
||||||
"default_bosminer_ssh_password": "root",
|
"default_bosminer_ssh_password": "root",
|
||||||
|
|||||||
@@ -138,6 +138,15 @@ class VNishWebAPI(BaseWebAPI):
|
|||||||
async def settings(self) -> dict:
|
async def settings(self) -> dict:
|
||||||
return await self.send_command("settings")
|
return await self.send_command("settings")
|
||||||
|
|
||||||
|
async def set_power_limit(self, wattage: int) -> bool:
|
||||||
|
# Can only set power limit to tuned preset
|
||||||
|
settings = await self.settings()
|
||||||
|
settings["miner"]["overclock"]["preset"] = str(wattage)
|
||||||
|
new_settings = {"miner": {"overclock": settings["miner"]["overclock"]}}
|
||||||
|
|
||||||
|
# response will always be {"restart_required":false,"reboot_required":false} even if unsuccessful
|
||||||
|
return await self.send_command("settings", privileged=True, **new_settings)
|
||||||
|
|
||||||
async def autotune_presets(self) -> dict:
|
async def autotune_presets(self) -> dict:
|
||||||
return await self.send_command("autotune/presets")
|
return await self.send_command("autotune/presets")
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pyasic"
|
name = "pyasic"
|
||||||
version = "0.65.1"
|
version = "0.67.1"
|
||||||
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"
|
||||||
|
|||||||
Reference in New Issue
Block a user