Compare commits
90 Commits
hammer_sup
...
v0.66.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
0327d93a35 | ||
|
|
680584c468 | ||
|
|
c0dbafb198 | ||
|
|
97d2c4ac34 | ||
|
|
055d633c91 | ||
|
|
68c57f265f | ||
|
|
1ba0f8ed83 | ||
|
|
7f74b083d3 | ||
|
|
97c20dae0a | ||
|
|
09c7aff640 | ||
|
|
7e7cdc9615 | ||
|
|
b6fb0fd2b9 | ||
|
|
46788e7d14 | ||
|
|
5b4f84a241 | ||
|
|
0c56bfdf9e | ||
|
|
4a5d793cd6 | ||
|
|
1894ff1aea | ||
|
|
3ab9294000 | ||
|
|
5e0641634b | ||
|
|
a1975bc9b8 | ||
|
|
6a265f03f7 | ||
|
|
c3658f028f | ||
|
|
ba3c653a29 | ||
|
|
61fbc132ed | ||
|
|
3f9f232990 | ||
|
|
29c2398846 | ||
|
|
ecc161820d | ||
|
|
5fec3052f6 | ||
|
|
437ee774ab | ||
|
|
aed9e0e406 | ||
|
|
be96428823 | ||
|
|
446881b237 | ||
|
|
ceab8e55b5 | ||
|
|
e12f85c94d | ||
|
|
0c85f53177 | ||
|
|
0b524f9bd0 | ||
|
|
95db852636 | ||
|
|
93fa02412a | ||
|
|
edb77e9cd8 | ||
|
|
cbf7eeb08d | ||
|
|
d34b35a82d | ||
|
|
5d57f35475 | ||
|
|
c95491ea45 | ||
|
|
e9ec43fac9 | ||
|
|
42bde081c4 | ||
|
|
bfb72aec1b | ||
|
|
b2f36b2f0b | ||
|
|
f75c07401b | ||
|
|
01b96227e0 | ||
|
|
82552390c8 | ||
|
|
b0651e26b8 | ||
|
|
c00802e311 | ||
|
|
d66739e2c9 | ||
|
|
65ed565220 | ||
|
|
db6499800b | ||
|
|
cc97ceee61 | ||
|
|
3fa1cb18d9 | ||
|
|
cb3c50d007 | ||
|
|
2523ef8484 | ||
|
|
01342738b0 | ||
|
|
a9dee4a911 | ||
|
|
883ffe20b4 |
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 }}
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
|
name: check-yaml for mkdocs.yml
|
||||||
|
files: ^mkdocs\.yml$
|
||||||
|
args: [--unsafe]
|
||||||
|
- id: check-yaml
|
||||||
|
name: check-yaml for other YAML files
|
||||||
|
exclude: ^mkdocs\.yml$
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 24.10.0
|
rev: 24.10.0
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
# .readthedocs.yaml
|
# .readthedocs.yaml
|
||||||
# Read the Docs configuration file
|
|
||||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
|
||||||
|
|
||||||
# Required
|
|
||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
# Set the version of Python and other tools you might need
|
# Set the version of Python and other tools you might need
|
||||||
build:
|
build:
|
||||||
os: ubuntu-20.04
|
os: ubuntu-20.04
|
||||||
tools:
|
tools: { python: "3.11" }
|
||||||
python: "3.9"
|
jobs:
|
||||||
|
pre_create_environment:
|
||||||
|
- asdf plugin add poetry
|
||||||
|
- asdf install poetry latest
|
||||||
|
- asdf global poetry latest
|
||||||
|
- poetry config virtualenvs.create false
|
||||||
|
post_install:
|
||||||
|
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --only docs
|
||||||
|
|
||||||
mkdocs:
|
mkdocs:
|
||||||
configuration: mkdocs.yml
|
configuration: mkdocs.yml
|
||||||
|
|
||||||
# Optionally declare the Python requirements required to build your docs
|
|
||||||
python:
|
|
||||||
install:
|
|
||||||
- requirements: docs/requirements.txt
|
|
||||||
@@ -53,6 +53,8 @@ def backend_str(backend: MinerTypes) -> str:
|
|||||||
return "Stock Firmware BitAxe Miners"
|
return "Stock Firmware BitAxe Miners"
|
||||||
case MinerTypes.ICERIVER:
|
case MinerTypes.ICERIVER:
|
||||||
return "Stock Firmware IceRiver Miners"
|
return "Stock Firmware IceRiver Miners"
|
||||||
|
case MinerTypes.HAMMER:
|
||||||
|
return "Stock Firmware Hammer Miners"
|
||||||
|
|
||||||
|
|
||||||
def create_url_str(mtype: str):
|
def create_url_str(mtype: str):
|
||||||
|
|||||||
189
docs/index.md
189
docs/index.md
@@ -11,145 +11,149 @@
|
|||||||
[](https://pyasic.readthedocs.io/en/latest/)
|
[](https://pyasic.readthedocs.io/en/latest/)
|
||||||
[](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
|
[](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
|
||||||
|
|
||||||
---
|
|
||||||
## Intro
|
## Intro
|
||||||
---
|
---
|
||||||
Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with ASIC miners on your network, which makes it super fast.
|
Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with ASIC miners on your network, which makes it super fast.
|
||||||
|
|
||||||
[Click here to view supported miner types](miners/supported_types.md)
|
[Click here to view supported miner types](miners/supported_types.md)
|
||||||
|
|
||||||
---
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
It is recommended to install `pyasic` in a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#what-other-popular-options-exist-aside-from-venv) to isolate it from the rest of your system. Options include:
|
|
||||||
- [pypoetry](https://python-poetry.org/): the reccommended way, since pyasic already uses it by default
|
|
||||||
|
|
||||||
```
|
|
||||||
poetry install
|
|
||||||
```
|
|
||||||
|
|
||||||
- [venv](https://docs.python.org/3/library/venv.html): included in Python standard library but has fewer features than other options
|
|
||||||
- [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv): [pyenv](https://github.com/pyenv/pyenv) plugin for managing virtualenvs
|
|
||||||
|
|
||||||
```
|
|
||||||
pyenv install <python version number>
|
|
||||||
pyenv virtualenv <python version number> <env name>
|
|
||||||
pyenv activate <env name>
|
|
||||||
```
|
|
||||||
|
|
||||||
- [conda](https://docs.conda.io/en/latest/)
|
|
||||||
|
|
||||||
##### Installing `pyasic`
|
|
||||||
|
|
||||||
`python -m pip install pyasic` or `poetry install`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
It is recommended to install `pyasic` in a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#what-other-popular-options-exist-aside-from-venv) to isolate it from the rest of your system.
|
||||||
|
`pyasic` can be installed directly from pip, either with `pip install pyasic`, or a different command if using a tool like `pypoetry`.
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
---
|
---
|
||||||
Getting started with `pyasic` is easy. First, find your miner (or miners) on the network by scanning for them or getting the correct class automatically for them if you know the IP.
|
Getting started with `pyasic` is easy. First, find your miner (or miners) on the network by scanning for them or getting the correct class automatically for them if you know the IP.
|
||||||
|
|
||||||
##### Scanning for miners
|
### Scanning for miners
|
||||||
To scan for miners in `pyasic`, we use the class [`MinerNetwork`][pyasic.network.MinerNetwork], which abstracts the search, communication, identification, setup, and return of a miner to 1 command.
|
To scan for miners in `pyasic`, we use the class [`MinerNetwork`][pyasic.network.MinerNetwork], which abstracts the search, communication, identification, setup, and return of a miner to 1 command.
|
||||||
The command [`MinerNetwork.scan()`][pyasic.network.MinerNetwork.scan] returns a list that contains any miners found.
|
The command [`MinerNetwork.scan()`][pyasic.network.MinerNetwork.scan] returns a list that contains any miners found.
|
||||||
```python
|
```python3
|
||||||
import asyncio # asyncio for handling the async part
|
import asyncio# (1)!
|
||||||
from pyasic.network import MinerNetwork # miner network handles the scanning
|
from pyasic.network import MinerNetwork# (2)!
|
||||||
|
|
||||||
|
|
||||||
async def scan_miners(): # define async scan function to allow awaiting
|
async def scan_miners():# (3)!
|
||||||
# create a miner network
|
network = MinerNetwork.from_subnet("192.168.1.50/24")# (4)!
|
||||||
# you can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs).
|
|
||||||
network = MinerNetwork.from_subnet("192.168.1.50/24") # this uses the 192.168.1.0-255 network
|
|
||||||
|
|
||||||
# scan for miners asynchronously
|
miners = await network.scan()# (5)!
|
||||||
# this will return the correct type of miners if they are supported with all functionality.
|
|
||||||
miners = await network.scan()
|
|
||||||
print(miners)
|
print(miners)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(scan_miners()) # run the scan asynchronously with asyncio.run()
|
asyncio.run(scan_miners())# (6)!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
1. `asyncio` for handling the async part.
|
||||||
|
2. `MinerNetwork` handles the scanning.
|
||||||
|
3. Define an async function to allow awaiting.
|
||||||
|
4. Create a miner network.
|
||||||
|
You can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs).
|
||||||
|
This uses the 192.168.1.0-255 network.
|
||||||
|
5. Scan for miners asynchronously.
|
||||||
|
This will return the correct type of miners (if they are supported) with all functionality.
|
||||||
|
6. Run the scan asynchronously with asyncio.run().
|
||||||
|
|
||||||
---
|
---
|
||||||
##### Creating miners based on IP
|
### Creating miners based on IP
|
||||||
If you already know the IP address of your miner or miners, you can use the [`MinerFactory`][pyasic.miners.factory.MinerFactory] to communicate and identify the miners, or an abstraction of its functionality, [`get_miner()`][pyasic.miners.get_miner].
|
If you already know the IP address of your miner or miners, you can use the [`MinerFactory`][pyasic.miners.factory.MinerFactory] to communicate and identify the miners, or an abstraction of its functionality, [`get_miner()`][pyasic.miners.get_miner].
|
||||||
The function [`get_miner()`][pyasic.miners.get_miner] will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.
|
The function [`get_miner()`][pyasic.miners.get_miner] will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.
|
||||||
```python
|
```python
|
||||||
import asyncio # asyncio for handling the async part
|
import asyncio# (1)!
|
||||||
from pyasic import get_miner # handles miner creation
|
from pyasic import get_miner# (2)!
|
||||||
|
|
||||||
|
|
||||||
async def get_miners(): # define async scan function to allow awaiting
|
async def get_miners():# (3)!
|
||||||
# get the miner with the miner factory
|
miner_1 = await get_miner("192.168.1.75")# (4)!
|
||||||
# the miner factory is a singleton, and will always use the same object and cache
|
|
||||||
# this means you can always call it as MinerFactory().get_miner(), or just get_miner()
|
|
||||||
miner_1 = await get_miner("192.168.1.75")
|
|
||||||
miner_2 = await get_miner("192.168.1.76")
|
miner_2 = await get_miner("192.168.1.76")
|
||||||
print(miner_1, miner_2)
|
print(miner_1, miner_2)
|
||||||
|
|
||||||
# can also gather these, since they are async
|
|
||||||
# gathering them will get them both at the same time
|
|
||||||
# this makes it much faster to get a lot of miners at a time
|
|
||||||
tasks = [get_miner("192.168.1.75"), get_miner("192.168.1.76")]
|
tasks = [get_miner("192.168.1.75"), get_miner("192.168.1.76")]
|
||||||
miners = await asyncio.gather(*tasks)
|
miners = await asyncio.gather(*tasks)# (5)!
|
||||||
print(miners)
|
print(miners)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(get_miners()) # get the miners asynchronously with asyncio.run()
|
asyncio.run(get_miners())# (6)!
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
1. `asyncio` for handling the async part.
|
||||||
|
2. `get_miner` handles the miner type selection.
|
||||||
|
3. Define an async function to allow awaiting.
|
||||||
|
4. Get the miner.
|
||||||
|
5. Can also gather these, since they are async.
|
||||||
|
Gathering them will get them both at the same time.
|
||||||
|
This makes it much faster to get a lot of miners at a time.
|
||||||
|
6. Get the miners asynchronously with asyncio.run().
|
||||||
|
|
||||||
## Data gathering
|
## Data gathering
|
||||||
---
|
---
|
||||||
Once you have your miner(s) identified, you will likely want to get data from the miner(s). You can do this using a built-in function in each miner called `get_data()`.
|
Once you have your miner(s) identified, you will likely want to get data from the miner(s). You can do this using a built-in function in each miner called `get_data()`.
|
||||||
This function will return an instance of the dataclass [`MinerData`][pyasic.data.MinerData] with all data it can gather from the miner.
|
This function will return an instance of the dataclass [`MinerData`][pyasic.data.MinerData] with all data it can gather from the miner.
|
||||||
Each piece of data in a [`MinerData`][pyasic.data.MinerData] instance can be referenced by getting it as an attribute, such as [`MinerData().hashrate`][pyasic.data.MinerData].
|
Each piece of data in a [`MinerData`][pyasic.data.MinerData] instance can be referenced by getting it as an attribute, such as [`MinerData().hashrate`][pyasic.data.MinerData].
|
||||||
|
|
||||||
##### One miner
|
### One miner
|
||||||
```python
|
```python
|
||||||
import asyncio
|
import asyncio# (1)!
|
||||||
from pyasic import get_miner
|
from pyasic import get_miner# (2)!
|
||||||
|
|
||||||
async def gather_miner_data():
|
|
||||||
miner = await get_miner("192.168.1.75")
|
async def gather_miner_data():# (3)!
|
||||||
if miner is not None:
|
miner = await get_miner("192.168.1.75")# (4)!
|
||||||
miner_data = await miner.get_data()
|
if miner is not None:# (5)!
|
||||||
print(miner_data) # all data from the dataclass
|
miner_data = await miner.get_data()# (6)!
|
||||||
|
print(miner_data)# (7)!
|
||||||
print(miner_data.hashrate) # hashrate of the miner in TH/s
|
print(miner_data.hashrate) # hashrate of the miner in TH/s
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(gather_miner_data())
|
asyncio.run(gather_miner_data())# (9)!
|
||||||
```
|
```
|
||||||
---
|
|
||||||
##### Multiple miners
|
1. `asyncio` for handling the async part.
|
||||||
|
2. `get_miner` handles the miner type selection.
|
||||||
|
3. Define an async function to allow awaiting.
|
||||||
|
4. Get the miner.
|
||||||
|
5. Make sure the miner exists.
|
||||||
|
If this result is `None`, the miner may be offline.
|
||||||
|
6. Get data from the miner.
|
||||||
|
7. All the data from the dataclass.
|
||||||
|
8. Hashrate of the miner, with unit information.
|
||||||
|
9. Get the miner data asynchronously with asyncio.run().
|
||||||
|
|
||||||
|
### Multiple miners
|
||||||
You can do something similar with multiple miners, with only needing to make a small change to get all the data at once.
|
You can do something similar with multiple miners, with only needing to make a small change to get all the data at once.
|
||||||
```python
|
```python
|
||||||
import asyncio # asyncio for handling the async part
|
import asyncio# (1)!
|
||||||
from pyasic.network import MinerNetwork # miner network handles the scanning
|
from pyasic.network import MinerNetwork# (2)!
|
||||||
|
|
||||||
|
|
||||||
async def gather_miner_data(): # define async scan function to allow awaiting
|
async def gather_miner_data():# (3)!
|
||||||
network = MinerNetwork.from_subnet("192.168.1.50/24")
|
network = MinerNetwork.from_subnet("192.168.1.50/24")# (4)!
|
||||||
miners = await network.scan()
|
miners = await network.scan()# (5)!
|
||||||
|
|
||||||
# we need to asyncio.gather() all the miners get_data() functions to make them run together
|
|
||||||
all_miner_data = await asyncio.gather(*[miner.get_data() for miner in miners])
|
all_miner_data = await asyncio.gather(*[miner.get_data() for miner in miners])
|
||||||
|
|
||||||
for miner_data in all_miner_data:
|
for miner_data in all_miner_data:
|
||||||
print(miner_data) # print out all the data one by one
|
print(miner_data)# (7)!
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(gather_miner_data())
|
asyncio.run(gather_miner_data())# (8)!
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
1. `asyncio` for handling the async part.
|
||||||
|
2. `MinerNetwork` handles the scanning.
|
||||||
|
3. Define an async function to allow awaiting.
|
||||||
|
4. Create a miner network.
|
||||||
|
5. Scan for miners asynchronously.
|
||||||
|
6. Use `asyncio.gather()` with all the miners' `get_data()` functions to make them run together.
|
||||||
|
7. Print out the data one at a time.
|
||||||
|
8. Get the miner data asynchronously with asyncio.run().
|
||||||
|
|
||||||
## Miner control
|
## Miner control
|
||||||
---
|
---
|
||||||
`pyasic` exposes a standard interface for each miner using control functions.
|
`pyasic` exposes a standard interface for each miner using control functions.
|
||||||
Every miner class in `pyasic` must implement all the control functions defined in [`MinerProtocol`][pyasic.miners.base.MinerProtocol].
|
Every miner class in `pyasic` must implement all the following control functions.
|
||||||
|
|
||||||
These functions are
|
|
||||||
[`check_light`][pyasic.miners.base.MinerProtocol.check_light],
|
[`check_light`][pyasic.miners.base.MinerProtocol.check_light],
|
||||||
[`fault_light_off`][pyasic.miners.base.MinerProtocol.fault_light_off],
|
[`fault_light_off`][pyasic.miners.base.MinerProtocol.fault_light_off],
|
||||||
[`fault_light_on`][pyasic.miners.base.MinerProtocol.fault_light_on],
|
[`fault_light_on`][pyasic.miners.base.MinerProtocol.fault_light_on],
|
||||||
@@ -166,35 +170,41 @@ These functions are
|
|||||||
[`send_config`][pyasic.miners.base.MinerProtocol.send_config], and
|
[`send_config`][pyasic.miners.base.MinerProtocol.send_config], and
|
||||||
[`set_power_limit`][pyasic.miners.base.MinerProtocol.set_power_limit].
|
[`set_power_limit`][pyasic.miners.base.MinerProtocol.set_power_limit].
|
||||||
|
|
||||||
##### Usage
|
### Usage
|
||||||
```python
|
```python
|
||||||
import asyncio
|
import asyncio# (1)!
|
||||||
from pyasic import get_miner
|
from pyasic import get_miner# (2)!
|
||||||
|
|
||||||
|
|
||||||
async def set_fault_light():
|
async def set_fault_light():# (3)!
|
||||||
miner = await get_miner("192.168.1.20")
|
miner = await get_miner("192.168.1.20")# (4)!
|
||||||
|
|
||||||
# call control function
|
await miner.fault_light_on()# (5)!
|
||||||
await miner.fault_light_on()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(set_fault_light())
|
asyncio.run(set_fault_light())# (6)!
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
1. `asyncio` for handling the async part.
|
||||||
|
2. `get_miner` handles the miner type selection.
|
||||||
|
3. Define an async function to allow awaiting.
|
||||||
|
4. Get the miner.
|
||||||
|
5. Call the miner control function.
|
||||||
|
6. Call the control function asynchronously with asyncio.run().
|
||||||
|
|
||||||
|
|
||||||
## Helper dataclasses
|
## Helper dataclasses
|
||||||
---
|
---
|
||||||
|
|
||||||
##### [`MinerConfig`][pyasic.config.MinerConfig] and [`MinerData`][pyasic.data.MinerData]
|
### [`MinerConfig`][pyasic.config.MinerConfig] and [`MinerData`][pyasic.data.MinerData]
|
||||||
|
|
||||||
`pyasic` implements a few dataclasses as helpers to make data return types consistent across different miners and miner APIs. The different fields of these dataclasses can all be viewed with the classmethod `cls.fields()`.
|
`pyasic` implements a few dataclasses as helpers to make data return types consistent across different miners and miner APIs. The different fields of these dataclasses can all be viewed with the classmethod `cls.fields()`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
##### [`MinerData`][pyasic.data.MinerData]
|
### [`MinerData`][pyasic.data.MinerData]
|
||||||
|
|
||||||
[`MinerData`][pyasic.data.MinerData] is a return from the [`get_data()`](#get-data) function, and is used to have a consistent dataset across all returns.
|
[`MinerData`][pyasic.data.MinerData] is a return from the [`get_data()`][pyasic.miners.base.MinerProtocol.get_data] function, and is used to have a consistent dataset across all returns.
|
||||||
|
|
||||||
You can call [`MinerData.as_dict()`][pyasic.data.MinerData.as_dict] to get the dataclass as a dictionary, and there are many other helper functions contained in the class to convert to different data formats.
|
You can call [`MinerData.as_dict()`][pyasic.data.MinerData.as_dict] to get the dataclass as a dictionary, and there are many other helper functions contained in the class to convert to different data formats.
|
||||||
|
|
||||||
@@ -213,13 +223,13 @@ average_data = sum(list_of_miner_data, start=MinerData("0.0.0.0"))/len(list_of_m
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
##### [`MinerConfig`][pyasic.config.MinerConfig]
|
### [`MinerConfig`][pyasic.config.MinerConfig]
|
||||||
|
|
||||||
[`MinerConfig`][pyasic.config.MinerConfig] is `pyasic`'s way to represent a configuration file from a miner.
|
[`MinerConfig`][pyasic.config.MinerConfig] is `pyasic`'s way to represent a configuration file from a miner.
|
||||||
It is designed to unionize the configuration of all supported miner types, and is the return from [`get_config()`](#get-config).
|
It is designed to unionize the configuration of all supported miner types, and is the return from [`get_config()`][pyasic.miners.base.MinerProtocol.get_config].
|
||||||
|
|
||||||
Each miner has a unique way to convert the [`MinerConfig`][pyasic.config.MinerConfig] to their specific type, there are helper functions in the class.
|
Each miner has a unique way to convert the [`MinerConfig`][pyasic.config.MinerConfig] to their specific type, there are helper functions in the class.
|
||||||
In most cases these helper functions should not be used, as [`send_config()`](#send-config) takes a [`MinerConfig`][pyasic.config.MinerConfig] and will do the conversion to the right type for you.
|
In most cases these helper functions should not be used, as [`send_config()`][pyasic.miners.base.MinerProtocol.send_config] takes a [`MinerConfig`][pyasic.config.MinerConfig] and will do the conversion to the right type for you.
|
||||||
|
|
||||||
You can use the [`MinerConfig`][pyasic.config.MinerConfig] as follows:
|
You can use the [`MinerConfig`][pyasic.config.MinerConfig] as follows:
|
||||||
```python
|
```python
|
||||||
@@ -241,7 +251,6 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
## Settings
|
## Settings
|
||||||
---
|
---
|
||||||
`pyasic` has settings designed to make using large groups of miners easier. You can set the default password for all types of miners using the `pyasic.settings` module, used as follows:
|
`pyasic` has settings designed to make using large groups of miners easier. You can set the default password for all types of miners using the `pyasic.settings` module, used as follows:
|
||||||
@@ -252,7 +261,7 @@ from pyasic import settings
|
|||||||
settings.update("default_antminer_web_password", "my_pwd")
|
settings.update("default_antminer_web_password", "my_pwd")
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Default values:
|
### Default values:
|
||||||
```
|
```
|
||||||
"network_ping_retries": 1,
|
"network_ping_retries": 1,
|
||||||
"network_ping_timeout": 3,
|
"network_ping_timeout": 3,
|
||||||
|
|||||||
@@ -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,6 +365,20 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro (Hive)
|
||||||
|
::: pyasic.miners.antminer.hiveon.X19.S19.HiveonS19jPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
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
|
||||||
|
|||||||
@@ -15,6 +15,13 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## D7 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X7.D7.BMMinerD7
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## L7 (VNish)
|
## L7 (VNish)
|
||||||
::: pyasic.miners.antminer.vnish.X7.L7.VnishL7
|
::: pyasic.miners.antminer.vnish.X7.L7.VnishL7
|
||||||
handler: python
|
handler: python
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## D9 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X9.D9.BMMinerD9
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## S9 (Stock)
|
## S9 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9
|
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9
|
||||||
handler: python
|
handler: python
|
||||||
@@ -36,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
|
||||||
@@ -43,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
|
||||||
|
|||||||
@@ -10,8 +10,3 @@ You may not instantiate this class on its own, only subclass from it.
|
|||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
::: pyasic.miners.base.MinerProtocol
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|||||||
@@ -22,3 +22,10 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## Gamma (Stock)
|
||||||
|
::: pyasic.miners.bitaxe.espminer.BM.BM1370.BitAxeGamma
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +1,10 @@
|
|||||||
## Control functionality
|
## Control functionality
|
||||||
|
|
||||||
### Check Light
|
All control functionality is outlined by the [`MinerProtocol`][pyasic.miners.base.MinerProtocol] class.
|
||||||
::: pyasic.miners.base.MinerProtocol.check_light
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Fault Light Off
|
## Miner Protocol
|
||||||
::: pyasic.miners.base.MinerProtocol.fault_light_off
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Fault Light On
|
::: pyasic.miners.base.MinerProtocol
|
||||||
::: pyasic.miners.base.MinerProtocol.fault_light_on
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Get Config
|
|
||||||
::: pyasic.miners.base.MinerProtocol.get_config
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Get Data
|
|
||||||
::: pyasic.miners.base.MinerProtocol.get_data
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Get Errors
|
|
||||||
::: pyasic.miners.base.MinerProtocol.get_errors
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Get Hostname
|
|
||||||
::: pyasic.miners.base.MinerProtocol.get_hostname
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Get Model
|
|
||||||
::: pyasic.miners.base.MinerProtocol.get_model
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Reboot
|
|
||||||
::: pyasic.miners.base.MinerProtocol.reboot
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Restart Backend
|
|
||||||
::: pyasic.miners.base.MinerProtocol.restart_backend
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Stop Mining
|
|
||||||
::: pyasic.miners.base.MinerProtocol.stop_mining
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Resume Mining
|
|
||||||
::: pyasic.miners.base.MinerProtocol.resume_mining
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Is Mining
|
|
||||||
::: pyasic.miners.base.MinerProtocol.is_mining
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Send Config
|
|
||||||
::: pyasic.miners.base.MinerProtocol.send_config
|
|
||||||
handler: python
|
|
||||||
options:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Set Power Limit
|
|
||||||
::: pyasic.miners.base.MinerProtocol.set_power_limit
|
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|||||||
10
docs/miners/hammer/DX.md
Normal file
10
docs/miners/hammer/DX.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# pyasic
|
||||||
|
## DX Models
|
||||||
|
|
||||||
|
## D10 (Stock)
|
||||||
|
::: pyasic.miners.hammer.blackminer.DX.D10.HammerD10
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -37,16 +37,19 @@ details {
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X7#l7-stock">L7 (Stock)</a></li>
|
<li><a href="../antminer/X7#l7-stock">L7 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X7#k7-stock">K7 (Stock)</a></li>
|
<li><a href="../antminer/X7#k7-stock">K7 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X7#d7-stock">D7 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X9 Series:</summary>
|
<summary>X9 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X9#e9pro-stock">E9Pro (Stock)</a></li>
|
<li><a href="../antminer/X9#e9pro-stock">E9Pro (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X9#d9-stock">D9 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X9#s9-stock">S9 (Stock)</a></li>
|
<li><a href="../antminer/X9#s9-stock">S9 (Stock)</a></li>
|
||||||
<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>
|
||||||
@@ -375,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>
|
||||||
@@ -529,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>
|
||||||
@@ -578,7 +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>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X19 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<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>
|
||||||
@@ -672,6 +684,7 @@ details {
|
|||||||
<li><a href="../bitaxe/BM#supra-stock">Supra (Stock)</a></li>
|
<li><a href="../bitaxe/BM#supra-stock">Supra (Stock)</a></li>
|
||||||
<li><a href="../bitaxe/BM#ultra-stock">Ultra (Stock)</a></li>
|
<li><a href="../bitaxe/BM#ultra-stock">Ultra (Stock)</a></li>
|
||||||
<li><a href="../bitaxe/BM#max-stock">Max (Stock)</a></li>
|
<li><a href="../bitaxe/BM#max-stock">Max (Stock)</a></li>
|
||||||
|
<li><a href="../bitaxe/BM#gamma-stock">Gamma (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -694,4 +707,15 @@ details {
|
|||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Stock Firmware Hammer Miners:</summary>
|
||||||
|
<ul>
|
||||||
|
<details>
|
||||||
|
<summary>DX Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../hammer/DX#d10-stock">D10 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
jinja2<3.1.4
|
|
||||||
mkdocs
|
|
||||||
mkdocstrings[python]
|
|
||||||
zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
||||||
33
mkdocs.yml
33
mkdocs.yml
@@ -1,5 +1,34 @@
|
|||||||
site_name: pyasic
|
site_name: pyasic
|
||||||
repo_url: https://github.com/UpstreamData/pyasic
|
repo_url: https://github.com/UpstreamData/pyasic
|
||||||
|
site_url: !ENV SITE_URL
|
||||||
|
theme:
|
||||||
|
name: material
|
||||||
|
features:
|
||||||
|
- content.code.copy
|
||||||
|
- content.code.annotate
|
||||||
|
palette:
|
||||||
|
- media: "(prefers-color-scheme)"
|
||||||
|
toggle:
|
||||||
|
icon: material/brightness-auto
|
||||||
|
name: Switch to light mode
|
||||||
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
|
toggle:
|
||||||
|
icon: material/weather-night
|
||||||
|
name: Switch to dark mode
|
||||||
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
|
toggle:
|
||||||
|
icon: material/weather-sunny
|
||||||
|
name: Switch to auto mode
|
||||||
|
markdown_extensions:
|
||||||
|
- pymdownx.highlight:
|
||||||
|
anchor_linenums: true
|
||||||
|
line_spans: __span
|
||||||
|
pygments_lang_class: true
|
||||||
|
- pymdownx.inlinehilite
|
||||||
|
- pymdownx.snippets
|
||||||
|
- pymdownx.superfences
|
||||||
nav:
|
nav:
|
||||||
- Introduction: "index.md"
|
- Introduction: "index.md"
|
||||||
- Miners:
|
- Miners:
|
||||||
@@ -50,6 +79,7 @@ nav:
|
|||||||
- Antminer X17: "miners/antminer/X17.md"
|
- Antminer X17: "miners/antminer/X17.md"
|
||||||
- Antminer X19: "miners/antminer/X19.md"
|
- Antminer X19: "miners/antminer/X19.md"
|
||||||
- Antminer X21: "miners/antminer/X21.md"
|
- Antminer X21: "miners/antminer/X21.md"
|
||||||
|
- Avalon Nano: "miners/avalonminer/nano.md"
|
||||||
- Avalon 7X: "miners/avalonminer/A7X.md"
|
- Avalon 7X: "miners/avalonminer/A7X.md"
|
||||||
- Avalon 8X: "miners/avalonminer/A8X.md"
|
- Avalon 8X: "miners/avalonminer/A8X.md"
|
||||||
- Avalon 9X: "miners/avalonminer/A9X.md"
|
- Avalon 9X: "miners/avalonminer/A9X.md"
|
||||||
@@ -62,6 +92,7 @@ nav:
|
|||||||
- Whatsminer M6X: "miners/whatsminer/M6X.md"
|
- Whatsminer M6X: "miners/whatsminer/M6X.md"
|
||||||
- Innosilicon T3X: "miners/innosilicon/T3X.md"
|
- Innosilicon T3X: "miners/innosilicon/T3X.md"
|
||||||
- Innosilicon A10X: "miners/innosilicon/A10X.md"
|
- Innosilicon A10X: "miners/innosilicon/A10X.md"
|
||||||
|
- Innosilicon A11X: "miners/innosilicon/A11X.md"
|
||||||
- Goldshell X5: "miners/goldshell/X5.md"
|
- Goldshell X5: "miners/goldshell/X5.md"
|
||||||
- Goldshell XMax: "miners/goldshell/XMax.md"
|
- Goldshell XMax: "miners/goldshell/XMax.md"
|
||||||
- Goldshell XBox: "miners/goldshell/XBox.md"
|
- Goldshell XBox: "miners/goldshell/XBox.md"
|
||||||
@@ -70,6 +101,8 @@ nav:
|
|||||||
- Auradine AT: "miners/auradine/AT.md"
|
- Auradine AT: "miners/auradine/AT.md"
|
||||||
- Blockminer: "miners/blockminer/blockminer.md"
|
- Blockminer: "miners/blockminer/blockminer.md"
|
||||||
- BitAxe BM: "miners/bitaxe/BM.md"
|
- BitAxe BM: "miners/bitaxe/BM.md"
|
||||||
|
- Hammer DX: "miners/hammer/DX.md"
|
||||||
|
- Iceriver KSX: "miners/iceriver/KSX.md"
|
||||||
- Base Miner: "miners/base_miner.md"
|
- Base Miner: "miners/base_miner.md"
|
||||||
- Settings:
|
- Settings:
|
||||||
- Settings: "settings/settings.md"
|
- Settings: "settings/settings.md"
|
||||||
|
|||||||
597
poetry.lock
generated
597
poetry.lock
generated
@@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aiofiles"
|
name = "aiofiles"
|
||||||
@@ -11,6 +11,17 @@ files = [
|
|||||||
{file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
|
{file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "annotated-types"
|
||||||
|
version = "0.7.0"
|
||||||
|
description = "Reusable constraint types to use with typing.Annotated"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
|
||||||
|
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.6.2.post1"
|
version = "4.6.2.post1"
|
||||||
@@ -57,6 +68,20 @@ pkcs11 = ["python-pkcs11 (>=0.7.0)"]
|
|||||||
pyopenssl = ["pyOpenSSL (>=23.0.0)"]
|
pyopenssl = ["pyOpenSSL (>=23.0.0)"]
|
||||||
pywin32 = ["pywin32 (>=227)"]
|
pywin32 = ["pywin32 (>=227)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "babel"
|
||||||
|
version = "2.16.0"
|
||||||
|
description = "Internationalization utilities"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"},
|
||||||
|
{file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "betterproto"
|
name = "betterproto"
|
||||||
version = "2.0.0b7"
|
version = "2.0.0b7"
|
||||||
@@ -178,6 +203,120 @@ files = [
|
|||||||
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "charset-normalizer"
|
||||||
|
version = "3.4.0"
|
||||||
|
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7.0"
|
||||||
|
files = [
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"},
|
||||||
|
{file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"},
|
||||||
|
{file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"},
|
||||||
|
{file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.1.7"
|
version = "8.1.7"
|
||||||
@@ -380,13 +519,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpcore"
|
name = "httpcore"
|
||||||
version = "1.0.6"
|
version = "1.0.7"
|
||||||
description = "A minimal low-level HTTP client."
|
description = "A minimal low-level HTTP client."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"},
|
{file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"},
|
||||||
{file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"},
|
{file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -401,13 +540,13 @@ trio = ["trio (>=0.22.0,<1.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpx"
|
name = "httpx"
|
||||||
version = "0.27.2"
|
version = "0.28.0"
|
||||||
description = "The next generation HTTP client."
|
description = "The next generation HTTP client."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"},
|
{file = "httpx-0.28.0-py3-none-any.whl", hash = "sha256:dc0b419a0cfeb6e8b34e85167c0da2671206f5095f1baa9663d23bcfd6b535fc"},
|
||||||
{file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"},
|
{file = "httpx-0.28.0.tar.gz", hash = "sha256:0858d3bab51ba7e386637f22a61d8ccddaeec5f3fe4209da3a6168dbb91573e0"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -415,7 +554,6 @@ anyio = "*"
|
|||||||
certifi = "*"
|
certifi = "*"
|
||||||
httpcore = "==1.*"
|
httpcore = "==1.*"
|
||||||
idna = "*"
|
idna = "*"
|
||||||
sniffio = "*"
|
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
brotli = ["brotli", "brotlicffi"]
|
brotli = ["brotli", "brotlicffi"]
|
||||||
@@ -437,13 +575,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "identify"
|
name = "identify"
|
||||||
version = "2.6.1"
|
version = "2.6.3"
|
||||||
description = "File identification library for Python"
|
description = "File identification library for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"},
|
{file = "identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd"},
|
||||||
{file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"},
|
{file = "identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@@ -681,24 +819,68 @@ platformdirs = ">=2.2.0"
|
|||||||
pyyaml = ">=5.1"
|
pyyaml = ">=5.1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mkdocstrings"
|
name = "mkdocs-material"
|
||||||
version = "0.20.0"
|
version = "9.5.47"
|
||||||
description = "Automatic documentation from sources, for MkDocs."
|
description = "Documentation that simply works"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "mkdocstrings-0.20.0-py3-none-any.whl", hash = "sha256:f17fc2c4f760ec302b069075ef9e31045aa6372ca91d2f35ded3adba8e25a472"},
|
{file = "mkdocs_material-9.5.47-py3-none-any.whl", hash = "sha256:53fb9c9624e7865da6ec807d116cd7be24b3cb36ab31b1d1d1a9af58c56009a2"},
|
||||||
{file = "mkdocstrings-0.20.0.tar.gz", hash = "sha256:c757f4f646d4f939491d6bc9256bfe33e36c5f8026392f49eaa351d241c838e5"},
|
{file = "mkdocs_material-9.5.47.tar.gz", hash = "sha256:fc3b7a8e00ad896660bd3a5cc12ca0cb28bdc2bcbe2a946b5714c23ac91b0ede"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
babel = ">=2.10,<3.0"
|
||||||
|
colorama = ">=0.4,<1.0"
|
||||||
|
jinja2 = ">=3.0,<4.0"
|
||||||
|
markdown = ">=3.2,<4.0"
|
||||||
|
mkdocs = ">=1.6,<2.0"
|
||||||
|
mkdocs-material-extensions = ">=1.3,<2.0"
|
||||||
|
paginate = ">=0.5,<1.0"
|
||||||
|
pygments = ">=2.16,<3.0"
|
||||||
|
pymdown-extensions = ">=10.2,<11.0"
|
||||||
|
regex = ">=2022.4"
|
||||||
|
requests = ">=2.26,<3.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"]
|
||||||
|
imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"]
|
||||||
|
recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mkdocs-material-extensions"
|
||||||
|
version = "1.3.1"
|
||||||
|
description = "Extension pack for Python Markdown and MkDocs Material."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"},
|
||||||
|
{file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mkdocstrings"
|
||||||
|
version = "0.26.2"
|
||||||
|
description = "Automatic documentation from sources, for MkDocs."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
files = [
|
||||||
|
{file = "mkdocstrings-0.26.2-py3-none-any.whl", hash = "sha256:1248f3228464f3b8d1a15bd91249ce1701fe3104ac517a5f167a0e01ca850ba5"},
|
||||||
|
{file = "mkdocstrings-0.26.2.tar.gz", hash = "sha256:34a8b50f1e6cfd29546c6c09fbe02154adfb0b361bb758834bf56aa284ba876e"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
click = ">=7.0"
|
||||||
|
importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
|
||||||
Jinja2 = ">=2.11.1"
|
Jinja2 = ">=2.11.1"
|
||||||
Markdown = ">=3.3"
|
Markdown = ">=3.6"
|
||||||
MarkupSafe = ">=1.1"
|
MarkupSafe = ">=1.1"
|
||||||
mkdocs = ">=1.2"
|
mkdocs = ">=1.4"
|
||||||
mkdocs-autorefs = ">=0.3.1"
|
mkdocs-autorefs = ">=1.2"
|
||||||
mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""}
|
mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""}
|
||||||
|
platformdirs = ">=2.2"
|
||||||
pymdown-extensions = ">=6.3"
|
pymdown-extensions = ">=6.3"
|
||||||
|
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.10\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
crystal = ["mkdocstrings-crystal (>=0.3.4)"]
|
crystal = ["mkdocstrings-crystal (>=0.3.4)"]
|
||||||
@@ -707,18 +889,19 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mkdocstrings-python"
|
name = "mkdocstrings-python"
|
||||||
version = "1.8.0"
|
version = "1.12.2"
|
||||||
description = "A Python handler for mkdocstrings."
|
description = "A Python handler for mkdocstrings."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "mkdocstrings_python-1.8.0-py3-none-any.whl", hash = "sha256:4209970cc90bec194568682a535848a8d8489516c6ed4adbe58bbc67b699ca9d"},
|
{file = "mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a"},
|
||||||
{file = "mkdocstrings_python-1.8.0.tar.gz", hash = "sha256:1488bddf50ee42c07d9a488dddc197f8e8999c2899687043ec5dd1643d057192"},
|
{file = "mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
griffe = ">=0.37"
|
griffe = ">=0.49"
|
||||||
mkdocstrings = ">=0.20"
|
mkdocs-autorefs = ">=1.2"
|
||||||
|
mkdocstrings = ">=0.26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multidict"
|
name = "multidict"
|
||||||
@@ -837,15 +1020,30 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "24.1"
|
version = "24.2"
|
||||||
description = "Core utilities for Python packages"
|
description = "Core utilities for Python packages"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
|
||||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paginate"
|
||||||
|
version = "0.5.7"
|
||||||
|
description = "Divides large result sets into pages for easier browsing"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"},
|
||||||
|
{file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pytest", "tox"]
|
||||||
|
lint = ["black"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "passlib"
|
name = "passlib"
|
||||||
version = "1.7.4"
|
version = "1.7.4"
|
||||||
@@ -936,6 +1134,152 @@ files = [
|
|||||||
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic"
|
||||||
|
version = "2.10.3"
|
||||||
|
description = "Data validation using Python type hints"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"},
|
||||||
|
{file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
annotated-types = ">=0.6.0"
|
||||||
|
pydantic-core = "2.27.1"
|
||||||
|
typing-extensions = ">=4.12.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
email = ["email-validator (>=2.0.0)"]
|
||||||
|
timezone = ["tzdata"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic-core"
|
||||||
|
version = "2.27.1"
|
||||||
|
description = "Core functionality for Pydantic validation and serialization"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"},
|
||||||
|
{file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"},
|
||||||
|
{file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"},
|
||||||
|
{file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.18.0"
|
||||||
|
description = "Pygments is a syntax highlighting package written in Python."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
|
||||||
|
{file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
windows-terminal = ["colorama (>=0.4.6)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pymdown-extensions"
|
name = "pymdown-extensions"
|
||||||
version = "10.12"
|
version = "10.12"
|
||||||
@@ -1044,6 +1388,130 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pyyaml = "*"
|
pyyaml = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "2024.11.6"
|
||||||
|
description = "Alternative regular expression module, to replace re."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"},
|
||||||
|
{file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"},
|
||||||
|
{file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"},
|
||||||
|
{file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"},
|
||||||
|
{file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"},
|
||||||
|
{file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"},
|
||||||
|
{file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"},
|
||||||
|
{file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.32.3"
|
||||||
|
description = "Python HTTP for Humans."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
||||||
|
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = ">=2017.4.17"
|
||||||
|
charset-normalizer = ">=2,<4"
|
||||||
|
idna = ">=2.5,<4"
|
||||||
|
urllib3 = ">=1.21.1,<3"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||||
|
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "six"
|
name = "six"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@@ -1068,13 +1536,43 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tomli"
|
name = "tomli"
|
||||||
version = "2.0.2"
|
version = "2.2.1"
|
||||||
description = "A lil' TOML parser"
|
description = "A lil' TOML parser"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"},
|
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
|
||||||
{file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"},
|
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
|
||||||
|
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
|
||||||
|
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1099,15 +1597,32 @@ files = [
|
|||||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "2.2.3"
|
||||||
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
|
||||||
|
{file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||||
|
h2 = ["h2 (>=4,<5)"]
|
||||||
|
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
zstd = ["zstandard (>=0.18.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtualenv"
|
name = "virtualenv"
|
||||||
version = "20.27.1"
|
version = "20.28.0"
|
||||||
description = "Virtual Python Environment builder"
|
description = "Virtual Python Environment builder"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"},
|
{file = "virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0"},
|
||||||
{file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"},
|
{file = "virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -1163,13 +1678,13 @@ watchmedo = ["PyYAML (>=3.10)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zipp"
|
name = "zipp"
|
||||||
version = "3.20.2"
|
version = "3.21.0"
|
||||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"},
|
{file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"},
|
||||||
{file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"},
|
{file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@@ -1183,4 +1698,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 = "c0aa00dd5f3b52bbac53eb765be2bca2ec7f9429e835d6b2fe6bf207f2f39974"
|
||||||
|
|||||||
@@ -13,25 +13,28 @@
|
|||||||
# 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 dataclasses import asdict, dataclass, field
|
|
||||||
|
|
||||||
from pyasic.config.fans import FanModeConfig
|
from pydantic import BaseModel, Field
|
||||||
from pyasic.config.mining import MiningModeConfig
|
|
||||||
|
from pyasic.config.fans import FanMode, FanModeConfig, FanModeNormal
|
||||||
|
from pyasic.config.mining import MiningMode, MiningModeConfig
|
||||||
from pyasic.config.mining.scaling import ScalingConfig
|
from pyasic.config.mining.scaling import ScalingConfig
|
||||||
from pyasic.config.pools import PoolConfig
|
from pyasic.config.pools import PoolConfig
|
||||||
from pyasic.config.temperature import TemperatureConfig
|
from pyasic.config.temperature import TemperatureConfig
|
||||||
from pyasic.misc import merge_dicts
|
from pyasic.misc import merge_dicts
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class MinerConfig(BaseModel):
|
||||||
class MinerConfig:
|
|
||||||
"""Represents the configuration for a miner including pool configuration,
|
"""Represents the configuration for a miner including pool configuration,
|
||||||
fan mode, temperature settings, mining mode, and power scaling."""
|
fan mode, temperature settings, mining mode, and power scaling."""
|
||||||
|
|
||||||
pools: PoolConfig = field(default_factory=PoolConfig.default)
|
class Config:
|
||||||
fan_mode: FanModeConfig = field(default_factory=FanModeConfig.default)
|
arbitrary_types_allowed = True
|
||||||
temperature: TemperatureConfig = field(default_factory=TemperatureConfig.default)
|
|
||||||
mining_mode: MiningModeConfig = field(default_factory=MiningModeConfig.default)
|
pools: PoolConfig = Field(default_factory=PoolConfig.default)
|
||||||
|
fan_mode: FanMode = Field(default_factory=FanModeConfig.default)
|
||||||
|
temperature: TemperatureConfig = Field(default_factory=TemperatureConfig.default)
|
||||||
|
mining_mode: MiningMode = Field(default_factory=MiningModeConfig.default)
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
try:
|
try:
|
||||||
@@ -41,7 +44,7 @@ class MinerConfig:
|
|||||||
|
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
"""Converts the MinerConfig object to a dictionary."""
|
"""Converts the MinerConfig object to a dictionary."""
|
||||||
return asdict(self)
|
return self.model_dump()
|
||||||
|
|
||||||
def as_am_modern(self, user_suffix: str = None) -> dict:
|
def as_am_modern(self, user_suffix: str = None) -> dict:
|
||||||
"""Generates the configuration in the format suitable for modern Antminers."""
|
"""Generates the configuration in the format suitable for modern Antminers."""
|
||||||
@@ -107,7 +110,7 @@ class MinerConfig:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def as_boser(self, user_suffix: str = None) -> dict:
|
def as_boser(self, user_suffix: str = None) -> dict:
|
||||||
""" "Generates the configuration in the format suitable for BOSer."""
|
"""Generates the configuration in the format suitable for BOSer."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_boser(),
|
**self.fan_mode.as_boser(),
|
||||||
**self.temperature.as_boser(),
|
**self.temperature.as_boser(),
|
||||||
@@ -156,6 +159,19 @@ class MinerConfig:
|
|||||||
**self.pools.as_luxos(user_suffix=user_suffix),
|
**self.pools.as_luxos(user_suffix=user_suffix),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str = None) -> dict:
|
||||||
|
main_cfg = {
|
||||||
|
"miner": {
|
||||||
|
**self.fan_mode.as_vnish(),
|
||||||
|
**self.temperature.as_vnish(),
|
||||||
|
**self.mining_mode.as_vnish(),
|
||||||
|
**self.pools.as_vnish(user_suffix=user_suffix),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isinstance(self.fan_mode, FanModeNormal):
|
||||||
|
main_cfg["miner"]["cooling"]["mode"]["param"] = self.temperature.target
|
||||||
|
return main_cfg
|
||||||
|
|
||||||
def as_hammer(self, *args, **kwargs) -> dict:
|
def as_hammer(self, *args, **kwargs) -> dict:
|
||||||
return self.as_am_modern(*args, **kwargs)
|
return self.as_am_modern(*args, **kwargs)
|
||||||
|
|
||||||
@@ -229,13 +245,13 @@ class MinerConfig:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict) -> "MinerConfig":
|
def from_vnish(cls, web_settings: dict, web_presets: list[dict]) -> "MinerConfig":
|
||||||
"""Constructs a MinerConfig object from web settings for VNish miners."""
|
"""Constructs a MinerConfig object from web settings for VNish miners."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_vnish(web_settings),
|
pools=PoolConfig.from_vnish(web_settings),
|
||||||
fan_mode=FanModeConfig.from_vnish(web_settings),
|
fan_mode=FanModeConfig.from_vnish(web_settings),
|
||||||
temperature=TemperatureConfig.from_vnish(web_settings),
|
temperature=TemperatureConfig.from_vnish(web_settings),
|
||||||
mining_mode=MiningModeConfig.from_vnish(web_settings),
|
mining_mode=MiningModeConfig.from_vnish(web_settings, web_presets),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -283,3 +299,7 @@ class MinerConfig:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_hammer(cls, *args, **kwargs) -> "MinerConfig":
|
def from_hammer(cls, *args, **kwargs) -> "MinerConfig":
|
||||||
return cls.from_am_modern(*args, **kwargs)
|
return cls.from_am_modern(*args, **kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_hiveon_modern(cls, web_conf: dict) -> "MinerConfig":
|
||||||
|
return cls.from_am_modern(web_conf)
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class MinerConfigOption(Enum):
|
class MinerConfigOption(Enum):
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -80,14 +81,13 @@ class MinerConfigOption(Enum):
|
|||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class MinerConfigValue(BaseModel):
|
||||||
class MinerConfigValue:
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None):
|
def from_dict(cls, dict_conf: dict | None):
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
return asdict(self)
|
return self.model_dump()
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|||||||
@@ -15,14 +15,15 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class FanModeNormal(MinerConfigValue):
|
class FanModeNormal(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="normal")
|
mode: str = Field(init=False, default="normal")
|
||||||
minimum_fans: int = 1
|
minimum_fans: int = 1
|
||||||
minimum_speed: int = 0
|
minimum_speed: int = 0
|
||||||
|
|
||||||
@@ -86,10 +87,21 @@ class FanModeNormal(MinerConfigValue):
|
|||||||
def as_luxos(self) -> dict:
|
def as_luxos(self) -> dict:
|
||||||
return {"fanset": {"speed": -1, "min_fans": self.minimum_fans}}
|
return {"fanset": {"speed": -1, "min_fans": self.minimum_fans}}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {
|
||||||
|
"cooling": {
|
||||||
|
"fan_min_count": self.minimum_fans,
|
||||||
|
"fan_min_duty": self.minimum_speed,
|
||||||
|
"mode": {
|
||||||
|
"name": "auto",
|
||||||
|
"param": None, # Target temp, must be set later...
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class FanModeManual(MinerConfigValue):
|
class FanModeManual(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="manual")
|
mode: str = Field(init=False, default="manual")
|
||||||
speed: int = 100
|
speed: int = 100
|
||||||
minimum_fans: int = 1
|
minimum_fans: int = 1
|
||||||
|
|
||||||
@@ -150,10 +162,21 @@ class FanModeManual(MinerConfigValue):
|
|||||||
def as_luxos(self) -> dict:
|
def as_luxos(self) -> dict:
|
||||||
return {"fanset": {"speed": self.speed, "min_fans": self.minimum_fans}}
|
return {"fanset": {"speed": self.speed, "min_fans": self.minimum_fans}}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {
|
||||||
|
"cooling": {
|
||||||
|
"fan_min_count": self.minimum_fans,
|
||||||
|
"fan_min_duty": self.speed,
|
||||||
|
"mode": {
|
||||||
|
"name": "manual",
|
||||||
|
"param": self.speed, # Speed value
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class FanModeImmersion(MinerConfigValue):
|
class FanModeImmersion(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="immersion")
|
mode: str = Field(init=False, default="immersion")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "FanModeImmersion":
|
def from_dict(cls, dict_conf: dict | None) -> "FanModeImmersion":
|
||||||
@@ -176,6 +199,9 @@ class FanModeImmersion(MinerConfigValue):
|
|||||||
def as_luxos(self) -> dict:
|
def as_luxos(self) -> dict:
|
||||||
return {"fanset": {"speed": 0, "min_fans": 0}}
|
return {"fanset": {"speed": 0, "min_fans": 0}}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {"cooling": {"mode": {"name": "immers"}}}
|
||||||
|
|
||||||
|
|
||||||
class FanModeConfig(MinerConfigOption):
|
class FanModeConfig(MinerConfigOption):
|
||||||
normal = FanModeNormal
|
normal = FanModeNormal
|
||||||
@@ -273,7 +299,7 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
keys = temperature_conf.keys()
|
keys = temperature_conf.keys()
|
||||||
if "auto" in keys:
|
if "auto" in keys:
|
||||||
if "minimumRequiredFans" in keys:
|
if "minimumRequiredFans" in keys:
|
||||||
return cls.normal(temperature_conf["minimumRequiredFans"])
|
return cls.normal(minimum_fans=temperature_conf["minimumRequiredFans"])
|
||||||
return cls.normal()
|
return cls.normal()
|
||||||
if "manual" in keys:
|
if "manual" in keys:
|
||||||
conf = {}
|
conf = {}
|
||||||
@@ -300,7 +326,9 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
mode = web_config["general-config"]["environment-profile"]
|
mode = web_config["general-config"]["environment-profile"]
|
||||||
if mode == "AirCooling":
|
if mode == "AirCooling":
|
||||||
if web_config["advance-config"]["override-fan-control"]:
|
if web_config["advance-config"]["override-fan-control"]:
|
||||||
return cls.manual(web_config["advance-config"]["fan-fixed-percent"])
|
return cls.manual(
|
||||||
|
speed=web_config["advance-config"]["fan-fixed-percent"]
|
||||||
|
)
|
||||||
return cls.normal()
|
return cls.normal()
|
||||||
return cls.immersion()
|
return cls.immersion()
|
||||||
except LookupError:
|
except LookupError:
|
||||||
@@ -333,3 +361,9 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
|
|
||||||
|
FanMode = TypeVar(
|
||||||
|
"FanMode",
|
||||||
|
bound=Union[FanModeNormal, FanModeManual, FanModeImmersion],
|
||||||
|
)
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import field
|
||||||
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
from pyasic import settings
|
from pyasic import settings
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
@@ -34,11 +35,11 @@ from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
|||||||
TunerPerformanceMode,
|
TunerPerformanceMode,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .algo import TunerAlgo
|
from .algo import TunerAlgo, TunerAlgoType
|
||||||
|
from .presets import MiningPreset
|
||||||
from .scaling import ScalingConfig
|
from .scaling import ScalingConfig
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeNormal(MinerConfigValue):
|
class MiningModeNormal(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="normal")
|
mode: str = field(init=False, default="normal")
|
||||||
|
|
||||||
@@ -74,7 +75,6 @@ class MiningModeNormal(MinerConfigValue):
|
|||||||
return {"autotunerset": {"enabled": False}}
|
return {"autotunerset": {"enabled": False}}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeSleep(MinerConfigValue):
|
class MiningModeSleep(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="sleep")
|
mode: str = field(init=False, default="sleep")
|
||||||
|
|
||||||
@@ -107,7 +107,6 @@ class MiningModeSleep(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeLPM(MinerConfigValue):
|
class MiningModeLPM(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="low")
|
mode: str = field(init=False, default="low")
|
||||||
|
|
||||||
@@ -130,7 +129,6 @@ class MiningModeLPM(MinerConfigValue):
|
|||||||
return {"settings": {"level": 1}}
|
return {"settings": {"level": 1}}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeHPM(MinerConfigValue):
|
class MiningModeHPM(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="high")
|
mode: str = field(init=False, default="high")
|
||||||
|
|
||||||
@@ -150,12 +148,14 @@ class MiningModeHPM(MinerConfigValue):
|
|||||||
return {"mode": {"mode": "turbo"}}
|
return {"mode": {"mode": "turbo"}}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModePowerTune(MinerConfigValue):
|
class MiningModePowerTune(MinerConfigValue):
|
||||||
|
class Config:
|
||||||
|
arbitrary_types_allowed = True
|
||||||
|
|
||||||
mode: str = field(init=False, default="power_tuning")
|
mode: str = field(init=False, default="power_tuning")
|
||||||
power: int = None
|
power: int | None = None
|
||||||
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
|
algo: TunerAlgoType = field(default_factory=TunerAlgo.default)
|
||||||
scaling: ScalingConfig = None
|
scaling: ScalingConfig | None = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
|
||||||
@@ -247,12 +247,14 @@ class MiningModePowerTune(MinerConfigValue):
|
|||||||
return {"autotunerset": {"enabled": True}}
|
return {"autotunerset": {"enabled": True}}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeHashrateTune(MinerConfigValue):
|
class MiningModeHashrateTune(MinerConfigValue):
|
||||||
|
class Config:
|
||||||
|
arbitrary_types_allowed = True
|
||||||
|
|
||||||
mode: str = field(init=False, default="hashrate_tuning")
|
mode: str = field(init=False, default="hashrate_tuning")
|
||||||
hashrate: int = None
|
hashrate: int | None = None
|
||||||
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
|
algo: TunerAlgoType = field(default_factory=TunerAlgo.default)
|
||||||
scaling: ScalingConfig = None
|
scaling: ScalingConfig | None = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
|
||||||
@@ -343,7 +345,29 @@ class MiningModeHashrateTune(MinerConfigValue):
|
|||||||
return {"autotunerset": {"enabled": True}}
|
return {"autotunerset": {"enabled": True}}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class MiningModePreset(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="preset")
|
||||||
|
|
||||||
|
active_preset: MiningPreset
|
||||||
|
available_presets: list[MiningPreset] = field(default_factory=list)
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {"overclock": {**self.active_preset.as_vnish()}}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(
|
||||||
|
cls, web_overclock_settings: dict, web_presets: list[dict]
|
||||||
|
) -> "MiningModePreset":
|
||||||
|
active_preset = None
|
||||||
|
for preset in web_presets:
|
||||||
|
if preset["name"] == web_overclock_settings["preset"]:
|
||||||
|
active_preset = preset
|
||||||
|
return cls(
|
||||||
|
active_preset=MiningPreset.from_vnish(active_preset),
|
||||||
|
available_presets=[MiningPreset.from_vnish(p) for p in web_presets],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ManualBoardSettings(MinerConfigValue):
|
class ManualBoardSettings(MinerConfigValue):
|
||||||
freq: float
|
freq: float
|
||||||
volt: float
|
volt: float
|
||||||
@@ -357,8 +381,10 @@ class ManualBoardSettings(MinerConfigValue):
|
|||||||
return {"miner-mode": "0"}
|
return {"miner-mode": "0"}
|
||||||
return {"miner-mode": 0}
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {"freq": self.freq}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeManual(MinerConfigValue):
|
class MiningModeManual(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="manual")
|
mode: str = field(init=False, default="manual")
|
||||||
|
|
||||||
@@ -379,6 +405,18 @@ class MiningModeManual(MinerConfigValue):
|
|||||||
return {"miner-mode": "0"}
|
return {"miner-mode": "0"}
|
||||||
return {"miner-mode": 0}
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
chains = [b.as_vnish() for b in self.boards.values() if b.freq != 0]
|
||||||
|
return {
|
||||||
|
"overclock": {
|
||||||
|
"chains": chains if chains != [] else None,
|
||||||
|
"globals": {
|
||||||
|
"freq": int(self.global_freq),
|
||||||
|
"volt": int(self.global_volt),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_overclock_settings: dict) -> "MiningModeManual":
|
def from_vnish(cls, web_overclock_settings: dict) -> "MiningModeManual":
|
||||||
# will raise KeyError if it cant find the settings, values cannot be empty
|
# will raise KeyError if it cant find the settings, values cannot be empty
|
||||||
@@ -430,6 +468,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
sleep = MiningModeSleep
|
sleep = MiningModeSleep
|
||||||
power_tuning = MiningModePowerTune
|
power_tuning = MiningModePowerTune
|
||||||
hashrate_tuning = MiningModeHashrateTune
|
hashrate_tuning = MiningModeHashrateTune
|
||||||
|
preset = MiningModePreset
|
||||||
manual = MiningModeManual
|
manual = MiningModeManual
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -521,7 +560,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if autotuning_conf.get("psu_power_limit") is not None:
|
if autotuning_conf.get("psu_power_limit") is not None:
|
||||||
# old autotuning conf
|
# old autotuning conf
|
||||||
return cls.power_tuning(
|
return cls.power_tuning(
|
||||||
autotuning_conf["psu_power_limit"],
|
power=autotuning_conf["psu_power_limit"],
|
||||||
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
|
||||||
)
|
)
|
||||||
if autotuning_conf.get("mode") is not None:
|
if autotuning_conf.get("mode") is not None:
|
||||||
@@ -530,7 +569,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if mode == "power_target":
|
if mode == "power_target":
|
||||||
if autotuning_conf.get("power_target") is not None:
|
if autotuning_conf.get("power_target") is not None:
|
||||||
return cls.power_tuning(
|
return cls.power_tuning(
|
||||||
autotuning_conf["power_target"],
|
power=autotuning_conf["power_target"],
|
||||||
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
|
||||||
)
|
)
|
||||||
return cls.power_tuning(
|
return cls.power_tuning(
|
||||||
@@ -539,7 +578,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if mode == "hashrate_target":
|
if mode == "hashrate_target":
|
||||||
if autotuning_conf.get("hashrate_target") is not None:
|
if autotuning_conf.get("hashrate_target") is not None:
|
||||||
return cls.hashrate_tuning(
|
return cls.hashrate_tuning(
|
||||||
autotuning_conf["hashrate_target"],
|
hashrate=autotuning_conf["hashrate_target"],
|
||||||
scaling=ScalingConfig.from_bosminer(toml_conf, mode="hashrate"),
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="hashrate"),
|
||||||
)
|
)
|
||||||
return cls.hashrate_tuning(
|
return cls.hashrate_tuning(
|
||||||
@@ -547,7 +586,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict):
|
def from_vnish(cls, web_settings: dict, web_presets: list[dict]):
|
||||||
try:
|
try:
|
||||||
mode_settings = web_settings["miner"]["overclock"]
|
mode_settings = web_settings["miner"]["overclock"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -556,7 +595,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if mode_settings["preset"] == "disabled":
|
if mode_settings["preset"] == "disabled":
|
||||||
return MiningModeManual.from_vnish(mode_settings)
|
return MiningModeManual.from_vnish(mode_settings)
|
||||||
else:
|
else:
|
||||||
return cls.power_tuning(int(mode_settings["preset"]))
|
return MiningModePreset.from_vnish(mode_settings, web_presets)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_boser(cls, grpc_miner_conf: dict):
|
def from_boser(cls, grpc_miner_conf: dict):
|
||||||
@@ -571,7 +610,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if tuner_conf["tunerMode"] == 1:
|
if tuner_conf["tunerMode"] == 1:
|
||||||
if tuner_conf.get("powerTarget") is not None:
|
if tuner_conf.get("powerTarget") is not None:
|
||||||
return cls.power_tuning(
|
return cls.power_tuning(
|
||||||
tuner_conf["powerTarget"]["watt"],
|
power=tuner_conf["powerTarget"]["watt"],
|
||||||
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
|
||||||
)
|
)
|
||||||
return cls.power_tuning(
|
return cls.power_tuning(
|
||||||
@@ -581,7 +620,7 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if tuner_conf["tunerMode"] == 2:
|
if tuner_conf["tunerMode"] == 2:
|
||||||
if tuner_conf.get("hashrateTarget") is not None:
|
if tuner_conf.get("hashrateTarget") is not None:
|
||||||
return cls.hashrate_tuning(
|
return cls.hashrate_tuning(
|
||||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
|
hashrate=int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
|
||||||
scaling=ScalingConfig.from_boser(
|
scaling=ScalingConfig.from_boser(
|
||||||
grpc_miner_conf, mode="hashrate"
|
grpc_miner_conf, mode="hashrate"
|
||||||
),
|
),
|
||||||
@@ -592,13 +631,13 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
|
|
||||||
if tuner_conf.get("powerTarget") is not None:
|
if tuner_conf.get("powerTarget") is not None:
|
||||||
return cls.power_tuning(
|
return cls.power_tuning(
|
||||||
tuner_conf["powerTarget"]["watt"],
|
power=tuner_conf["powerTarget"]["watt"],
|
||||||
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
|
||||||
)
|
)
|
||||||
|
|
||||||
if tuner_conf.get("hashrateTarget") is not None:
|
if tuner_conf.get("hashrateTarget") is not None:
|
||||||
return cls.hashrate_tuning(
|
return cls.hashrate_tuning(
|
||||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
|
hashrate=int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
|
||||||
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="hashrate"),
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="hashrate"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -617,9 +656,9 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if mode_data.get("Mode") == "turbo":
|
if mode_data.get("Mode") == "turbo":
|
||||||
return cls.high()
|
return cls.high()
|
||||||
if mode_data.get("Ths") is not None:
|
if mode_data.get("Ths") is not None:
|
||||||
return cls.hashrate_tuning(mode_data["Ths"])
|
return cls.hashrate_tuning(hashrate=mode_data["Ths"])
|
||||||
if mode_data.get("Power") is not None:
|
if mode_data.get("Power") is not None:
|
||||||
return cls.power_tuning(mode_data["Power"])
|
return cls.power_tuning(power=mode_data["Power"])
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
@@ -647,3 +686,18 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
|
|
||||||
|
MiningMode = TypeVar(
|
||||||
|
"MiningMode",
|
||||||
|
bound=Union[
|
||||||
|
MiningModeNormal,
|
||||||
|
MiningModeHPM,
|
||||||
|
MiningModeLPM,
|
||||||
|
MiningModeSleep,
|
||||||
|
MiningModeManual,
|
||||||
|
MiningModePowerTune,
|
||||||
|
MiningModeHashrateTune,
|
||||||
|
MiningModePreset,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class StandardTuneAlgo(MinerConfigValue):
|
class StandardTuneAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="standard")
|
mode: str = field(init=False, default="standard")
|
||||||
|
|
||||||
@@ -13,7 +13,6 @@ class StandardTuneAlgo(MinerConfigValue):
|
|||||||
return VOptAlgo().as_epic()
|
return VOptAlgo().as_epic()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class VOptAlgo(MinerConfigValue):
|
class VOptAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="voltage_optimizer")
|
mode: str = field(init=False, default="voltage_optimizer")
|
||||||
|
|
||||||
@@ -21,7 +20,6 @@ class VOptAlgo(MinerConfigValue):
|
|||||||
return "VoltageOptimizer"
|
return "VoltageOptimizer"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class BoardTuneAlgo(MinerConfigValue):
|
class BoardTuneAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="board_tune")
|
mode: str = field(init=False, default="board_tune")
|
||||||
|
|
||||||
@@ -29,7 +27,6 @@ class BoardTuneAlgo(MinerConfigValue):
|
|||||||
return "BoardTune"
|
return "BoardTune"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ChipTuneAlgo(MinerConfigValue):
|
class ChipTuneAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="chip_tune")
|
mode: str = field(init=False, default="chip_tune")
|
||||||
|
|
||||||
@@ -37,7 +34,6 @@ class ChipTuneAlgo(MinerConfigValue):
|
|||||||
return "ChipTune"
|
return "ChipTune"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class TunerAlgo(MinerConfigOption):
|
class TunerAlgo(MinerConfigOption):
|
||||||
standard = StandardTuneAlgo
|
standard = StandardTuneAlgo
|
||||||
voltage_optimizer = VOptAlgo
|
voltage_optimizer = VOptAlgo
|
||||||
@@ -45,11 +41,11 @@ class TunerAlgo(MinerConfigOption):
|
|||||||
chip_tune = ChipTuneAlgo
|
chip_tune = ChipTuneAlgo
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls):
|
def default(cls) -> TunerAlgoType:
|
||||||
return cls.standard()
|
return cls.standard()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None):
|
def from_dict(cls, dict_conf: dict | None) -> TunerAlgoType:
|
||||||
mode = dict_conf.get("mode")
|
mode = dict_conf.get("mode")
|
||||||
if mode is None:
|
if mode is None:
|
||||||
return cls.default()
|
return cls.default()
|
||||||
@@ -57,3 +53,14 @@ class TunerAlgo(MinerConfigOption):
|
|||||||
cls_attr = getattr(cls, mode)
|
cls_attr = getattr(cls, mode)
|
||||||
if cls_attr is not None:
|
if cls_attr is not None:
|
||||||
return cls_attr().from_dict(dict_conf)
|
return cls_attr().from_dict(dict_conf)
|
||||||
|
|
||||||
|
|
||||||
|
TunerAlgoType = TypeVar(
|
||||||
|
"TunerAlgoType",
|
||||||
|
bound=Union[
|
||||||
|
StandardTuneAlgo,
|
||||||
|
VOptAlgo,
|
||||||
|
BoardTuneAlgo,
|
||||||
|
ChipTuneAlgo,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
34
pyasic/config/mining/presets.py
Normal file
34
pyasic/config/mining/presets.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
|
class MiningPreset(MinerConfigValue):
|
||||||
|
name: str | None = None
|
||||||
|
power: int | None = None
|
||||||
|
hashrate: int | None = None
|
||||||
|
tuned: bool | None = None
|
||||||
|
modded_psu: bool = False
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
if self.name is not None:
|
||||||
|
return {"preset": self.name}
|
||||||
|
return {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_preset: dict):
|
||||||
|
name = web_preset["name"]
|
||||||
|
hr_power_split = web_preset["pretty"].split("~")
|
||||||
|
if len(hr_power_split) == 1:
|
||||||
|
power = None
|
||||||
|
hashrate = None
|
||||||
|
else:
|
||||||
|
power = hr_power_split[0].replace("watt", "").strip()
|
||||||
|
hashrate = hr_power_split[1].replace("TH", "").replace(" LC", "").strip()
|
||||||
|
tuned = web_preset["status"] == "tuned"
|
||||||
|
modded_psu = web_preset["modded_psu_required"]
|
||||||
|
return cls(
|
||||||
|
name=name,
|
||||||
|
power=power,
|
||||||
|
hashrate=hashrate,
|
||||||
|
tuned=tuned,
|
||||||
|
modded_psu=modded_psu,
|
||||||
|
)
|
||||||
@@ -20,7 +20,6 @@ from dataclasses import dataclass
|
|||||||
from pyasic.config.base import MinerConfigValue
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ScalingShutdown(MinerConfigValue):
|
class ScalingShutdown(MinerConfigValue):
|
||||||
enabled: bool = False
|
enabled: bool = False
|
||||||
duration: int = None
|
duration: int = None
|
||||||
@@ -35,7 +34,9 @@ class ScalingShutdown(MinerConfigValue):
|
|||||||
def from_bosminer(cls, power_scaling_conf: dict):
|
def from_bosminer(cls, power_scaling_conf: dict):
|
||||||
sd_enabled = power_scaling_conf.get("shutdown_enabled")
|
sd_enabled = power_scaling_conf.get("shutdown_enabled")
|
||||||
if sd_enabled is not None:
|
if sd_enabled is not None:
|
||||||
return cls(sd_enabled, power_scaling_conf.get("shutdown_duration"))
|
return cls(
|
||||||
|
enabled=sd_enabled, duration=power_scaling_conf.get("shutdown_duration")
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -43,9 +44,12 @@ class ScalingShutdown(MinerConfigValue):
|
|||||||
sd_enabled = power_scaling_conf.get("shutdownEnabled")
|
sd_enabled = power_scaling_conf.get("shutdownEnabled")
|
||||||
if sd_enabled is not None:
|
if sd_enabled is not None:
|
||||||
try:
|
try:
|
||||||
return cls(sd_enabled, power_scaling_conf["shutdownDuration"]["hours"])
|
return cls(
|
||||||
|
enabled=sd_enabled,
|
||||||
|
duration=power_scaling_conf["shutdownDuration"]["hours"],
|
||||||
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return cls(sd_enabled)
|
return cls(enabled=sd_enabled)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
def as_bosminer(self) -> dict:
|
||||||
@@ -60,7 +64,6 @@ class ScalingShutdown(MinerConfigValue):
|
|||||||
return {"enable_shutdown": self.enabled, "shutdown_duration": self.duration}
|
return {"enable_shutdown": self.enabled, "shutdown_duration": self.duration}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ScalingConfig(MinerConfigValue):
|
class ScalingConfig(MinerConfigValue):
|
||||||
step: int = None
|
step: int = None
|
||||||
minimum: int = None
|
minimum: int = None
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigValue
|
from pyasic.config.base import MinerConfigValue
|
||||||
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
||||||
PoolConfiguration,
|
PoolConfiguration,
|
||||||
@@ -30,122 +31,99 @@ from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Pool(MinerConfigValue):
|
class Pool(MinerConfigValue):
|
||||||
url: str
|
url: str
|
||||||
user: str
|
user: str
|
||||||
password: str
|
password: str
|
||||||
|
|
||||||
def as_am_modern(self, user_suffix: str = None) -> dict:
|
def as_am_modern(self, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
return {
|
||||||
return {
|
"url": self.url,
|
||||||
"url": self.url,
|
"user": f"{self.user}{user_suffix or ''}",
|
||||||
"user": f"{self.user}{user_suffix}",
|
"pass": self.password,
|
||||||
"pass": self.password,
|
}
|
||||||
}
|
|
||||||
return {"url": self.url, "user": self.user, "pass": self.password}
|
|
||||||
|
|
||||||
def as_wm(self, idx: int = 1, user_suffix: str = None) -> dict:
|
def as_wm(self, idx: int = 1, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
|
||||||
return {
|
|
||||||
f"pool_{idx}": self.url,
|
|
||||||
f"worker_{idx}": f"{self.user}{user_suffix}",
|
|
||||||
f"passwd_{idx}": self.password,
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
f"pool_{idx}": self.url,
|
f"pool_{idx}": self.url,
|
||||||
f"worker_{idx}": self.user,
|
f"worker_{idx}": f"{self.user}{user_suffix or ''}",
|
||||||
f"passwd_{idx}": self.password,
|
f"passwd_{idx}": self.password,
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_am_old(self, idx: int = 1, user_suffix: str = None) -> dict:
|
def as_am_old(self, idx: int = 1, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
|
||||||
return {
|
|
||||||
f"_ant_pool{idx}url": self.url,
|
|
||||||
f"_ant_pool{idx}user": f"{self.user}{user_suffix}",
|
|
||||||
f"_ant_pool{idx}pw": self.password,
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
f"_ant_pool{idx}url": self.url,
|
f"_ant_pool{idx}url": self.url,
|
||||||
f"_ant_pool{idx}user": self.user,
|
f"_ant_pool{idx}user": f"{self.user}{user_suffix or ''}",
|
||||||
f"_ant_pool{idx}pw": self.password,
|
f"_ant_pool{idx}pw": self.password,
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_goldshell(self, user_suffix: str = None) -> dict:
|
def as_goldshell(self, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
return {
|
||||||
return {
|
"url": self.url,
|
||||||
"url": self.url,
|
"user": f"{self.user}{user_suffix or ''}",
|
||||||
"user": f"{self.user}{user_suffix}",
|
"pass": self.password,
|
||||||
"pass": self.password,
|
}
|
||||||
}
|
|
||||||
return {"url": self.url, "user": self.user, "pass": self.password}
|
|
||||||
|
|
||||||
def as_avalon(self, user_suffix: str = None) -> str:
|
def as_avalon(self, user_suffix: str | None = None) -> str:
|
||||||
if user_suffix is not None:
|
return ",".join([self.url, f"{self.user}{user_suffix or ''}", self.password])
|
||||||
return ",".join([self.url, f"{self.user}{user_suffix}", self.password])
|
|
||||||
return ",".join([self.url, self.user, self.password])
|
|
||||||
|
|
||||||
def as_inno(self, idx: int = 1, user_suffix: str = None) -> dict:
|
def as_inno(self, idx: int = 1, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
|
||||||
return {
|
|
||||||
f"Pool{idx}": self.url,
|
|
||||||
f"UserName{idx}": f"{self.user}{user_suffix}",
|
|
||||||
f"Password{idx}": self.password,
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
f"Pool{idx}": self.url,
|
f"Pool{idx}": self.url,
|
||||||
f"UserName{idx}": self.user,
|
f"UserName{idx}": f"{self.user}{user_suffix or ''}",
|
||||||
f"Password{idx}": self.password,
|
f"Password{idx}": self.password,
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_bosminer(self, user_suffix: str = None) -> dict:
|
def as_bosminer(self, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
return {
|
||||||
return {
|
"url": self.url,
|
||||||
"url": self.url,
|
"user": f"{self.user}{user_suffix or ''}",
|
||||||
"user": f"{self.user}{user_suffix}",
|
"password": self.password,
|
||||||
"password": self.password,
|
}
|
||||||
}
|
|
||||||
return {"url": self.url, "user": self.user, "password": self.password}
|
|
||||||
|
|
||||||
def as_auradine(self, user_suffix: str = None) -> dict:
|
def as_auradine(self, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
return {
|
||||||
return {
|
"url": self.url,
|
||||||
"url": self.url,
|
"user": f"{self.user}{user_suffix or ''}",
|
||||||
"user": f"{self.user}{user_suffix}",
|
"pass": self.password,
|
||||||
"pass": self.password,
|
}
|
||||||
}
|
|
||||||
return {"url": self.url, "user": self.user, "pass": self.password}
|
|
||||||
|
|
||||||
def as_epic(self, user_suffix: str = None):
|
def as_epic(self, user_suffix: str | None = None):
|
||||||
if user_suffix is not None:
|
return {
|
||||||
return {
|
"pool": self.url,
|
||||||
"pool": self.url,
|
"login": f"{self.user}{user_suffix or ''}",
|
||||||
"login": f"{self.user}{user_suffix}",
|
"password": self.password,
|
||||||
"password": self.password,
|
}
|
||||||
}
|
|
||||||
return {"pool": self.url, "login": self.user, "password": self.password}
|
|
||||||
|
|
||||||
def as_mara(self, user_suffix: str = None) -> dict:
|
def as_mara(self, user_suffix: str | None = None) -> dict:
|
||||||
if user_suffix is not None:
|
return {
|
||||||
return {
|
"url": self.url,
|
||||||
"url": self.url,
|
"user": f"{self.user}{user_suffix or ''}",
|
||||||
"user": f"{self.user}{user_suffix}",
|
"pass": self.password,
|
||||||
"pass": self.password,
|
}
|
||||||
}
|
|
||||||
return {"url": self.url, "user": self.user, "pass": self.password}
|
|
||||||
|
|
||||||
def as_bitaxe(self, user_suffix: str = None) -> dict:
|
def as_bitaxe(self, user_suffix: str | None = None) -> dict:
|
||||||
return {
|
return {
|
||||||
"stratumURL": self.url,
|
"stratumURL": self.url,
|
||||||
"stratumUser": f"{self.user}{user_suffix}",
|
"stratumUser": f"{self.user}{user_suffix or ''}",
|
||||||
"stratumPassword": self.password,
|
"stratumPassword": self.password,
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_boser(self) -> PoolConfiguration:
|
def as_boser(self, user_suffix: str | None = None) -> PoolConfiguration:
|
||||||
return PoolConfiguration(
|
return PoolConfiguration(
|
||||||
url=self.url, user=self.user, password=self.password, enabled=True
|
url=self.url,
|
||||||
|
user=f"{self.user}{user_suffix or ''}",
|
||||||
|
password=self.password,
|
||||||
|
enabled=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str | None = None) -> dict:
|
||||||
|
return {
|
||||||
|
"url": self.url,
|
||||||
|
"user": f"{self.user}{user_suffix or ''}",
|
||||||
|
"pass": self.password,
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "Pool":
|
def from_dict(cls, dict_conf: dict | None) -> "Pool":
|
||||||
return cls(
|
return cls(
|
||||||
@@ -192,7 +170,7 @@ class Pool(MinerConfigValue):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_pool: dict) -> "Pool":
|
def from_vnish(cls, web_pool: dict) -> "Pool":
|
||||||
return cls(
|
return cls(
|
||||||
url=web_pool["url"],
|
url="stratum+tcp://" + web_pool["url"],
|
||||||
user=web_pool["user"],
|
user=web_pool["user"],
|
||||||
password=web_pool["pass"],
|
password=web_pool["pass"],
|
||||||
)
|
)
|
||||||
@@ -235,11 +213,10 @@ class Pool(MinerConfigValue):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PoolGroup(MinerConfigValue):
|
class PoolGroup(MinerConfigValue):
|
||||||
pools: list[Pool] = field(default_factory=list)
|
pools: list[Pool] = Field(default_factory=list)
|
||||||
quota: int = 1
|
quota: int = 1
|
||||||
name: str = None
|
name: str | None = None
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.name is None:
|
if self.name is None:
|
||||||
@@ -247,18 +224,18 @@ class PoolGroup(MinerConfigValue):
|
|||||||
random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
|
random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
|
||||||
) # generate random pool group name in case it isn't set
|
) # generate random pool group name in case it isn't set
|
||||||
|
|
||||||
def as_am_modern(self, user_suffix: str = None) -> list:
|
def as_am_modern(self, user_suffix: str | None = None) -> list:
|
||||||
pools = []
|
pools = []
|
||||||
idx = 0
|
idx = 0
|
||||||
while idx < 3:
|
while idx < 3:
|
||||||
if len(self.pools) > idx:
|
if len(self.pools) > idx:
|
||||||
pools.append(self.pools[idx].as_am_modern(user_suffix=user_suffix))
|
pools.append(self.pools[idx].as_am_modern(user_suffix=user_suffix))
|
||||||
else:
|
else:
|
||||||
pools.append(Pool("", "", "").as_am_modern())
|
pools.append(Pool(url="", user="", password="").as_am_modern())
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
def as_wm(self, user_suffix: str = None) -> dict:
|
def as_wm(self, user_suffix: str | None = None) -> dict:
|
||||||
pools = {}
|
pools = {}
|
||||||
idx = 0
|
idx = 0
|
||||||
while idx < 3:
|
while idx < 3:
|
||||||
@@ -267,11 +244,11 @@ class PoolGroup(MinerConfigValue):
|
|||||||
**self.pools[idx].as_wm(idx=idx + 1, user_suffix=user_suffix)
|
**self.pools[idx].as_wm(idx=idx + 1, user_suffix=user_suffix)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pools.update(**Pool("", "", "").as_wm(idx=idx + 1))
|
pools.update(**Pool(url="", user="", password="").as_wm(idx=idx + 1))
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
def as_am_old(self, user_suffix: str = None) -> dict:
|
def as_am_old(self, user_suffix: str | None = None) -> dict:
|
||||||
pools = {}
|
pools = {}
|
||||||
idx = 0
|
idx = 0
|
||||||
while idx < 3:
|
while idx < 3:
|
||||||
@@ -280,19 +257,21 @@ class PoolGroup(MinerConfigValue):
|
|||||||
**self.pools[idx].as_am_old(idx=idx + 1, user_suffix=user_suffix)
|
**self.pools[idx].as_am_old(idx=idx + 1, user_suffix=user_suffix)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pools.update(**Pool("", "", "").as_am_old(idx=idx + 1))
|
pools.update(
|
||||||
|
**Pool(url="", user="", password="").as_am_old(idx=idx + 1)
|
||||||
|
)
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
def as_goldshell(self, user_suffix: str = None) -> list:
|
def as_goldshell(self, user_suffix: str | None = None) -> list:
|
||||||
return [pool.as_goldshell(user_suffix) for pool in self.pools]
|
return [pool.as_goldshell(user_suffix) for pool in self.pools]
|
||||||
|
|
||||||
def as_avalon(self, user_suffix: str = None) -> str:
|
def as_avalon(self, user_suffix: str | None = None) -> str:
|
||||||
if len(self.pools) > 0:
|
if len(self.pools) > 0:
|
||||||
return self.pools[0].as_avalon(user_suffix=user_suffix)
|
return self.pools[0].as_avalon(user_suffix=user_suffix)
|
||||||
return Pool("", "", "").as_avalon()
|
return Pool(url="", user="", password="").as_avalon()
|
||||||
|
|
||||||
def as_inno(self, user_suffix: str = None) -> dict:
|
def as_inno(self, user_suffix: str | None = None) -> dict:
|
||||||
pools = {}
|
pools = {}
|
||||||
idx = 0
|
idx = 0
|
||||||
while idx < 3:
|
while idx < 3:
|
||||||
@@ -301,11 +280,11 @@ class PoolGroup(MinerConfigValue):
|
|||||||
**self.pools[idx].as_inno(idx=idx + 1, user_suffix=user_suffix)
|
**self.pools[idx].as_inno(idx=idx + 1, user_suffix=user_suffix)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pools.update(**Pool("", "", "").as_inno(idx=idx + 1))
|
pools.update(**Pool(url="", user="", password="").as_inno(idx=idx + 1))
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
def as_bosminer(self, user_suffix: str = None) -> dict:
|
def as_bosminer(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.pools) > 0:
|
if len(self.pools) > 0:
|
||||||
conf = {
|
conf = {
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
@@ -318,25 +297,28 @@ class PoolGroup(MinerConfigValue):
|
|||||||
return conf
|
return conf
|
||||||
return {"name": "Group", "pool": []}
|
return {"name": "Group", "pool": []}
|
||||||
|
|
||||||
def as_auradine(self, user_suffix: str = None) -> list:
|
def as_auradine(self, user_suffix: str | None = None) -> list:
|
||||||
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
|
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
|
||||||
|
|
||||||
def as_epic(self, user_suffix: str = None) -> list:
|
def as_epic(self, user_suffix: str | None = None) -> list:
|
||||||
return [p.as_epic(user_suffix=user_suffix) for p in self.pools]
|
return [p.as_epic(user_suffix=user_suffix) for p in self.pools]
|
||||||
|
|
||||||
def as_mara(self, user_suffix: str = None) -> list:
|
def as_mara(self, user_suffix: str | None = None) -> list:
|
||||||
return [p.as_mara(user_suffix=user_suffix) for p in self.pools]
|
return [p.as_mara(user_suffix=user_suffix) for p in self.pools]
|
||||||
|
|
||||||
def as_bitaxe(self, user_suffix: str = None) -> dict:
|
def as_bitaxe(self, user_suffix: str | None = None) -> dict:
|
||||||
return self.pools[0].as_bitaxe(user_suffix=user_suffix)
|
return self.pools[0].as_bitaxe(user_suffix=user_suffix)
|
||||||
|
|
||||||
def as_boser(self, user_suffix: str = None) -> PoolGroupConfiguration:
|
def as_boser(self, user_suffix: str | None = None) -> PoolGroupConfiguration:
|
||||||
return PoolGroupConfiguration(
|
return PoolGroupConfiguration(
|
||||||
name=self.name,
|
name=self.name,
|
||||||
quota=Quota(value=self.quota),
|
quota=Quota(value=self.quota),
|
||||||
pools=[p.as_boser() for p in self.pools],
|
pools=[p.as_boser() for p in self.pools],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str | None = None) -> dict:
|
||||||
|
return {"pools": [p.as_vnish(user_suffix=user_suffix) for p in self.pools]}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
|
def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
|
||||||
cls_conf = {}
|
cls_conf = {}
|
||||||
@@ -371,11 +353,11 @@ class PoolGroup(MinerConfigValue):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_goldshell(cls, web_pools: list) -> "PoolGroup":
|
def from_goldshell(cls, web_pools: list) -> "PoolGroup":
|
||||||
return cls([Pool.from_goldshell(p) for p in web_pools])
|
return cls(pools=[Pool.from_goldshell(p) for p in web_pools])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_inno(cls, web_pools: list) -> "PoolGroup":
|
def from_inno(cls, web_pools: list) -> "PoolGroup":
|
||||||
return cls([Pool.from_inno(p) for p in web_pools])
|
return cls(pools=[Pool.from_inno(p) for p in web_pools])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_group_conf: dict) -> "PoolGroup":
|
def from_bosminer(cls, toml_group_conf: dict) -> "PoolGroup":
|
||||||
@@ -389,7 +371,9 @@ class PoolGroup(MinerConfigValue):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
||||||
return cls([Pool.from_vnish(p) for p in web_settings_pools])
|
return cls(
|
||||||
|
pools=[Pool.from_vnish(p) for p in web_settings_pools if p["url"] != ""]
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_boser(cls, grpc_pool_group: dict) -> "PoolGroup":
|
def from_boser(cls, grpc_pool_group: dict) -> "PoolGroup":
|
||||||
@@ -424,9 +408,8 @@ class PoolGroup(MinerConfigValue):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PoolConfig(MinerConfigValue):
|
class PoolConfig(MinerConfigValue):
|
||||||
groups: List[PoolGroup] = field(default_factory=list)
|
groups: List[PoolGroup] = Field(default_factory=list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls) -> "PoolConfig":
|
def default(cls) -> "PoolConfig":
|
||||||
@@ -448,44 +431,44 @@ class PoolConfig(MinerConfigValue):
|
|||||||
group_pools.append(pool)
|
group_pools.append(pool)
|
||||||
return cls(groups=[PoolGroup(pools=group_pools)])
|
return cls(groups=[PoolGroup(pools=group_pools)])
|
||||||
|
|
||||||
def as_am_modern(self, user_suffix: str = None) -> dict:
|
def as_am_modern(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {"pools": self.groups[0].as_am_modern(user_suffix=user_suffix)}
|
return {"pools": self.groups[0].as_am_modern(user_suffix=user_suffix)}
|
||||||
return {"pools": PoolGroup().as_am_modern()}
|
return {"pools": PoolGroup().as_am_modern()}
|
||||||
|
|
||||||
def as_wm(self, user_suffix: str = None) -> dict:
|
def as_wm(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {"pools": self.groups[0].as_wm(user_suffix=user_suffix)}
|
return {"pools": self.groups[0].as_wm(user_suffix=user_suffix)}
|
||||||
return {"pools": PoolGroup().as_wm()}
|
return {"pools": PoolGroup().as_wm()}
|
||||||
|
|
||||||
def as_am_old(self, user_suffix: str = None) -> dict:
|
def as_am_old(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return self.groups[0].as_am_old(user_suffix=user_suffix)
|
return self.groups[0].as_am_old(user_suffix=user_suffix)
|
||||||
return PoolGroup().as_am_old()
|
return PoolGroup().as_am_old()
|
||||||
|
|
||||||
def as_goldshell(self, user_suffix: str = None) -> dict:
|
def as_goldshell(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {"pools": self.groups[0].as_goldshell(user_suffix=user_suffix)}
|
return {"pools": self.groups[0].as_goldshell(user_suffix=user_suffix)}
|
||||||
return {"pools": PoolGroup().as_goldshell()}
|
return {"pools": PoolGroup().as_goldshell()}
|
||||||
|
|
||||||
def as_avalon(self, user_suffix: str = None) -> dict:
|
def as_avalon(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {"pools": self.groups[0].as_avalon(user_suffix=user_suffix)}
|
return {"pools": self.groups[0].as_avalon(user_suffix=user_suffix)}
|
||||||
return {"pools": PoolGroup().as_avalon()}
|
return {"pools": PoolGroup().as_avalon()}
|
||||||
|
|
||||||
def as_inno(self, user_suffix: str = None) -> dict:
|
def as_inno(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return self.groups[0].as_inno(user_suffix=user_suffix)
|
return self.groups[0].as_inno(user_suffix=user_suffix)
|
||||||
return PoolGroup().as_inno()
|
return PoolGroup().as_inno()
|
||||||
|
|
||||||
def as_bosminer(self, user_suffix: str = None) -> dict:
|
def as_bosminer(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {
|
return {
|
||||||
"group": [g.as_bosminer(user_suffix=user_suffix) for g in self.groups]
|
"group": [g.as_bosminer(user_suffix=user_suffix) for g in self.groups]
|
||||||
}
|
}
|
||||||
return {"group": [PoolGroup().as_bosminer()]}
|
return {"group": [PoolGroup().as_bosminer()]}
|
||||||
|
|
||||||
def as_boser(self, user_suffix: str = None) -> dict:
|
def as_boser(self, user_suffix: str | None = None) -> dict:
|
||||||
return {
|
return {
|
||||||
"set_pool_groups": SetPoolGroupsRequest(
|
"set_pool_groups": SetPoolGroupsRequest(
|
||||||
save_action=SaveAction.SAVE_AND_APPLY,
|
save_action=SaveAction.SAVE_AND_APPLY,
|
||||||
@@ -493,7 +476,7 @@ class PoolConfig(MinerConfigValue):
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_auradine(self, user_suffix: str = None) -> dict:
|
def as_auradine(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {
|
return {
|
||||||
"updatepools": {
|
"updatepools": {
|
||||||
@@ -502,7 +485,7 @@ class PoolConfig(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
return {"updatepools": {"pools": PoolGroup().as_auradine()}}
|
return {"updatepools": {"pools": PoolGroup().as_auradine()}}
|
||||||
|
|
||||||
def as_epic(self, user_suffix: str = None) -> dict:
|
def as_epic(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {
|
return {
|
||||||
"pools": {
|
"pools": {
|
||||||
@@ -519,17 +502,20 @@ class PoolConfig(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_mara(self, user_suffix: str = None) -> dict:
|
def as_mara(self, user_suffix: str | None = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
return {"pools": self.groups[0].as_mara(user_suffix=user_suffix)}
|
return {"pools": self.groups[0].as_mara(user_suffix=user_suffix)}
|
||||||
return {"pools": []}
|
return {"pools": []}
|
||||||
|
|
||||||
def as_bitaxe(self, user_suffix: str = None) -> dict:
|
def as_bitaxe(self, user_suffix: str | None = None) -> dict:
|
||||||
return self.groups[0].as_bitaxe(user_suffix=user_suffix)
|
return self.groups[0].as_bitaxe(user_suffix=user_suffix)
|
||||||
|
|
||||||
def as_luxos(self, user_suffix: str = None) -> dict:
|
def as_luxos(self, user_suffix: str | None = None) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str | None = None) -> dict:
|
||||||
|
return self.groups[0].as_vnish(user_suffix=user_suffix)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
||||||
try:
|
try:
|
||||||
@@ -538,38 +524,38 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return PoolConfig.default()
|
return PoolConfig.default()
|
||||||
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
||||||
|
|
||||||
return cls([PoolGroup.from_api(pool_data)])
|
return cls(groups=[PoolGroup.from_api(pool_data)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_epic(cls, web_conf: dict) -> "PoolConfig":
|
def from_epic(cls, web_conf: dict) -> "PoolConfig":
|
||||||
pool_data = web_conf["StratumConfigs"]
|
pool_data = web_conf["StratumConfigs"]
|
||||||
return cls([PoolGroup.from_epic(pool_data)])
|
return cls(groups=[PoolGroup.from_epic(pool_data)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
|
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
|
||||||
pool_data = web_conf["pools"]
|
pool_data = web_conf["pools"]
|
||||||
|
|
||||||
return cls([PoolGroup.from_am_modern(pool_data)])
|
return cls(groups=[PoolGroup.from_am_modern(pool_data)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_goldshell(cls, web_pools: list) -> "PoolConfig":
|
def from_goldshell(cls, web_pools: list) -> "PoolConfig":
|
||||||
return cls([PoolGroup.from_goldshell(web_pools)])
|
return cls(groups=[PoolGroup.from_goldshell(web_pools)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_inno(cls, web_pools: list) -> "PoolConfig":
|
def from_inno(cls, web_pools: list) -> "PoolConfig":
|
||||||
return cls([PoolGroup.from_inno(web_pools)])
|
return cls(groups=[PoolGroup.from_inno(web_pools)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_conf: dict) -> "PoolConfig":
|
def from_bosminer(cls, toml_conf: dict) -> "PoolConfig":
|
||||||
if toml_conf.get("group") is None:
|
if toml_conf.get("group") is None:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
return cls([PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
|
return cls(groups=[PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict) -> "PoolConfig":
|
def from_vnish(cls, web_settings: dict) -> "PoolConfig":
|
||||||
try:
|
try:
|
||||||
return cls([PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
return cls(groups=[PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ from dataclasses import dataclass
|
|||||||
from pyasic.config.base import MinerConfigValue
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class TemperatureConfig(MinerConfigValue):
|
class TemperatureConfig(MinerConfigValue):
|
||||||
target: int = None
|
target: int | None = None
|
||||||
hot: int = None
|
hot: int | None = None
|
||||||
danger: int = None
|
danger: int | None = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls):
|
def default(cls):
|
||||||
@@ -57,6 +56,9 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
def as_luxos(self) -> dict:
|
def as_luxos(self) -> dict:
|
||||||
return {"tempctrlset": [self.target or "", self.hot or "", self.danger or ""]}
|
return {"tempctrlset": [self.target or "", self.hot or "", self.danger or ""]}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {"misc": {"restart_temp": self.danger}}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "TemperatureConfig":
|
def from_dict(cls, dict_conf: dict | None) -> "TemperatureConfig":
|
||||||
return cls(
|
return cls(
|
||||||
@@ -96,9 +98,16 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
|
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
|
||||||
|
try:
|
||||||
|
dangerous_temp = web_settings["misc"]["restart_temp"]
|
||||||
|
except KeyError:
|
||||||
|
dangerous_temp = None
|
||||||
try:
|
try:
|
||||||
if web_settings["miner"]["cooling"]["mode"]["name"] == "auto":
|
if web_settings["miner"]["cooling"]["mode"]["name"] == "auto":
|
||||||
return cls(target=web_settings["miner"]["cooling"]["mode"]["param"])
|
return cls(
|
||||||
|
target=web_settings["miner"]["cooling"]["mode"]["param"],
|
||||||
|
danger=dangerous_temp,
|
||||||
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return cls()
|
return cls()
|
||||||
|
|||||||
@@ -15,25 +15,24 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import json
|
|
||||||
import time
|
import time
|
||||||
from dataclasses import asdict, dataclass, field, fields
|
|
||||||
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 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 .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
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class MinerData(BaseModel):
|
||||||
class MinerData:
|
|
||||||
"""A Dataclass to standardize data returned from miners (specifically `AnyMiner().get_data()`)
|
"""A Dataclass to standardize data returned from miners (specifically `AnyMiner().get_data()`)
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -50,7 +49,6 @@ class MinerData:
|
|||||||
fw_ver: The current firmware version on the miner as a str.
|
fw_ver: The current firmware version on the miner as a str.
|
||||||
hostname: The network hostname of the miner as a str.
|
hostname: The network hostname of the miner as a str.
|
||||||
hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
|
hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
|
||||||
_hashrate: Backup for hashrate found via API instead of hashboards.
|
|
||||||
expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
|
expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
|
||||||
hashboards: A list of [`HashBoard`][pyasic.data.HashBoard]s on the miner with their statistics.
|
hashboards: A list of [`HashBoard`][pyasic.data.HashBoard]s on the miner with their statistics.
|
||||||
temperature_avg: The average temperature across the boards. Calculated automatically.
|
temperature_avg: The average temperature across the boards. Calculated automatically.
|
||||||
@@ -77,58 +75,44 @@ class MinerData:
|
|||||||
|
|
||||||
# general
|
# general
|
||||||
ip: str
|
ip: str
|
||||||
_datetime: datetime = field(repr=False, default=None)
|
raw_datetime: datetime = Field(
|
||||||
datetime: str = field(init=False)
|
exclude=True, default_factory=datetime.now(timezone.utc).astimezone, repr=False
|
||||||
timestamp: int = field(init=False)
|
)
|
||||||
|
|
||||||
# about
|
# about
|
||||||
device_info: DeviceInfo = None
|
device_info: DeviceInfo | None = None
|
||||||
make: str = field(init=False)
|
mac: str | None = None
|
||||||
model: str = field(init=False)
|
api_ver: str | None = None
|
||||||
firmware: str = field(init=False)
|
fw_ver: str | None = None
|
||||||
algo: str = field(init=False)
|
hostname: str | None = None
|
||||||
mac: str = None
|
|
||||||
api_ver: str = None
|
|
||||||
fw_ver: str = None
|
|
||||||
hostname: str = None
|
|
||||||
|
|
||||||
# hashrate
|
# hashrate
|
||||||
hashrate: AlgoHashRate = field(init=False)
|
raw_hashrate: AlgoHashRateType = Field(exclude=True, default=None, repr=False)
|
||||||
_hashrate: AlgoHashRate = field(repr=False, default=None)
|
|
||||||
|
|
||||||
# expected
|
# expected
|
||||||
expected_hashrate: float = None
|
expected_hashrate: AlgoHashRateType | None = None
|
||||||
expected_hashboards: int = None
|
expected_hashboards: int | None = None
|
||||||
expected_chips: int = None
|
expected_chips: int | None = None
|
||||||
expected_fans: int = None
|
expected_fans: int | None = None
|
||||||
|
|
||||||
# % expected
|
|
||||||
percent_expected_chips: float = field(init=False)
|
|
||||||
percent_expected_hashrate: float = field(init=False)
|
|
||||||
percent_expected_wattage: float = field(init=False)
|
|
||||||
|
|
||||||
# temperature
|
# temperature
|
||||||
temperature_avg: int = field(init=False)
|
env_temp: float | None = None
|
||||||
env_temp: float = None
|
|
||||||
|
|
||||||
# power
|
# power
|
||||||
wattage: int = None
|
wattage: int | None = None
|
||||||
wattage_limit: int = field(init=False)
|
voltage: float | None = None
|
||||||
voltage: float = None
|
raw_wattage_limit: int | None = Field(exclude=True, default=None, repr=False)
|
||||||
_wattage_limit: int = field(repr=False, default=None)
|
|
||||||
|
|
||||||
# fans
|
# fans
|
||||||
fans: List[Fan] = field(default_factory=list)
|
fans: List[Fan] = Field(default_factory=list)
|
||||||
fan_psu: int = None
|
fan_psu: int | None = None
|
||||||
|
|
||||||
# boards
|
# boards
|
||||||
hashboards: List[HashBoard] = field(default_factory=list)
|
hashboards: List[HashBoard] = Field(default_factory=list)
|
||||||
total_chips: int = field(init=False)
|
|
||||||
nominal: bool = field(init=False)
|
|
||||||
|
|
||||||
# config
|
# config
|
||||||
config: MinerConfig = None
|
config: MinerConfig | None = None
|
||||||
fault_light: Union[bool, None] = None
|
fault_light: bool | None = None
|
||||||
|
|
||||||
# errors
|
# errors
|
||||||
errors: List[
|
errors: List[
|
||||||
@@ -138,30 +122,21 @@ class MinerData:
|
|||||||
X19Error,
|
X19Error,
|
||||||
InnosiliconError,
|
InnosiliconError,
|
||||||
]
|
]
|
||||||
] = field(default_factory=list)
|
] = Field(default_factory=list)
|
||||||
|
|
||||||
# mining state
|
# mining state
|
||||||
is_mining: bool = True
|
is_mining: bool = True
|
||||||
uptime: int = None
|
uptime: int | None = None
|
||||||
efficiency: int = field(init=False)
|
|
||||||
|
|
||||||
# pools
|
# pools
|
||||||
pools: list[PoolMetrics] = field(default_factory=list)
|
pools: list[PoolMetrics] = Field(default_factory=list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fields(cls):
|
def fields(cls):
|
||||||
return [f.name for f in fields(cls) if not f.name.startswith("_")]
|
return list(cls.model_fields.keys())
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def dict_factory(x):
|
|
||||||
return {
|
|
||||||
k: v.value if isinstance(v, Scheme) else v
|
|
||||||
for (k, v) in x
|
|
||||||
if not k.startswith("_")
|
|
||||||
}
|
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self._datetime = datetime.now(timezone.utc).astimezone()
|
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:
|
||||||
@@ -189,19 +164,19 @@ class MinerData:
|
|||||||
|
|
||||||
def __floordiv__(self, other):
|
def __floordiv__(self, other):
|
||||||
cp = copy.deepcopy(self)
|
cp = copy.deepcopy(self)
|
||||||
for key in self:
|
for key in self.fields():
|
||||||
item = getattr(self, key)
|
item = getattr(self, key)
|
||||||
if isinstance(item, int):
|
if isinstance(item, int):
|
||||||
setattr(cp, key, item // other)
|
setattr(cp, key, item // other)
|
||||||
if isinstance(item, float):
|
if isinstance(item, float):
|
||||||
setattr(cp, key, round(item / other, 2))
|
setattr(cp, key, item / other)
|
||||||
return cp
|
return cp
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
if not isinstance(other, MinerData):
|
if not isinstance(other, MinerData):
|
||||||
raise TypeError("Cannot add MinerData to non MinerData type.")
|
raise TypeError("Cannot add MinerData to non MinerData type.")
|
||||||
cp = copy.deepcopy(self)
|
cp = copy.deepcopy(self)
|
||||||
for key in self:
|
for key in self.fields():
|
||||||
item = getattr(self, key)
|
item = getattr(self, key)
|
||||||
other_item = getattr(other, key)
|
other_item = getattr(other, key)
|
||||||
if item is None:
|
if item is None:
|
||||||
@@ -221,34 +196,49 @@ class MinerData:
|
|||||||
setattr(cp, key, item & other_item)
|
setattr(cp, key, item & other_item)
|
||||||
return cp
|
return cp
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def hashrate(self): # noqa - Skip PyCharm inspection
|
def hashrate(self) -> AlgoHashRateType:
|
||||||
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])(0))
|
return sum(hr_data, start=type(hr_data[0])(rate=0))
|
||||||
return self._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._hashrate = val
|
self.raw_hashrate = val
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def wattage_limit(self): # noqa - Skip PyCharm inspection
|
def wattage_limit(self) -> int:
|
||||||
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
|
||||||
return self._wattage_limit
|
return self.raw_wattage_limit
|
||||||
|
|
||||||
@wattage_limit.setter
|
@wattage_limit.setter
|
||||||
def wattage_limit(self, val: int):
|
def wattage_limit(self, val: int):
|
||||||
self._wattage_limit = val
|
self.raw_wattage_limit = val
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def total_chips(self): # noqa - Skip PyCharm inspection
|
def total_chips(self) -> int | None:
|
||||||
if len(self.hashboards) > 0:
|
if len(self.hashboards) > 0:
|
||||||
chip_data = []
|
chip_data = []
|
||||||
for item in self.hashboards:
|
for item in self.hashboards:
|
||||||
@@ -258,34 +248,25 @@ class MinerData:
|
|||||||
return sum(chip_data)
|
return sum(chip_data)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@total_chips.setter
|
@computed_field # type: ignore[misc]
|
||||||
def total_chips(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nominal(self): # noqa - Skip PyCharm inspection
|
def nominal(self) -> bool | None:
|
||||||
if self.total_chips is None or self.expected_chips is None:
|
if self.total_chips is None or self.expected_chips is None:
|
||||||
return None
|
return None
|
||||||
return self.expected_chips == self.total_chips
|
return self.expected_chips == self.total_chips
|
||||||
|
|
||||||
@nominal.setter
|
@computed_field # type: ignore[misc]
|
||||||
def nominal(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def percent_expected_chips(self): # noqa - Skip PyCharm inspection
|
def percent_expected_chips(self) -> int | None:
|
||||||
if self.total_chips is None or self.expected_chips is None:
|
if self.total_chips is None or self.expected_chips is None:
|
||||||
return None
|
return None
|
||||||
if self.total_chips == 0 or self.expected_chips == 0:
|
if self.total_chips == 0 or self.expected_chips == 0:
|
||||||
return 0
|
return 0
|
||||||
return round((self.total_chips / self.expected_chips) * 100)
|
return round((self.total_chips / self.expected_chips) * 100)
|
||||||
|
|
||||||
@percent_expected_chips.setter
|
@computed_field # type: ignore[misc]
|
||||||
def percent_expected_chips(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def percent_expected_hashrate(self): # noqa - Skip PyCharm inspection
|
def percent_expected_hashrate(self) -> int | None:
|
||||||
if self.hashrate is None or self.expected_hashrate is None:
|
if self.hashrate is None or self.expected_hashrate is None:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@@ -293,12 +274,9 @@ class MinerData:
|
|||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@percent_expected_hashrate.setter
|
@computed_field # type: ignore[misc]
|
||||||
def percent_expected_hashrate(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def percent_expected_wattage(self): # noqa - Skip PyCharm inspection
|
def percent_expected_wattage(self) -> int | None:
|
||||||
if self.wattage_limit is None or self.wattage is None:
|
if self.wattage_limit is None or self.wattage is None:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@@ -306,12 +284,9 @@ class MinerData:
|
|||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@percent_expected_wattage.setter
|
@computed_field # type: ignore[misc]
|
||||||
def percent_expected_wattage(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def temperature_avg(self): # noqa - Skip PyCharm inspection
|
def temperature_avg(self) -> int | None:
|
||||||
total_temp = 0
|
total_temp = 0
|
||||||
temp_count = 0
|
temp_count = 0
|
||||||
for hb in self.hashboards:
|
for hb in self.hashboards:
|
||||||
@@ -322,12 +297,9 @@ class MinerData:
|
|||||||
return None
|
return None
|
||||||
return round(total_temp / temp_count)
|
return round(total_temp / temp_count)
|
||||||
|
|
||||||
@temperature_avg.setter
|
@computed_field # type: ignore[misc]
|
||||||
def temperature_avg(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def efficiency(self): # noqa - Skip PyCharm inspection
|
def efficiency(self) -> int | None:
|
||||||
if self.hashrate is None or self.wattage is None:
|
if self.hashrate is None or self.wattage is None:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@@ -335,67 +307,45 @@ class MinerData:
|
|||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@efficiency.setter
|
@computed_field # type: ignore[misc]
|
||||||
def efficiency(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def datetime(self): # noqa - Skip PyCharm inspection
|
def datetime(self) -> str:
|
||||||
return self._datetime.isoformat()
|
return self.raw_datetime.isoformat()
|
||||||
|
|
||||||
@datetime.setter
|
|
||||||
def datetime(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def timestamp(self): # noqa - Skip PyCharm inspection
|
def timestamp(self) -> int:
|
||||||
return int(time.mktime(self._datetime.timetuple()))
|
return int(time.mktime(self.raw_datetime.timetuple()))
|
||||||
|
|
||||||
@timestamp.setter
|
|
||||||
def timestamp(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def make(self): # noqa - Skip PyCharm inspection
|
def make(self) -> str:
|
||||||
if self.device_info.make is not None:
|
if self.device_info.make is not None:
|
||||||
return str(self.device_info.make)
|
return str(self.device_info.make)
|
||||||
|
|
||||||
@make.setter
|
@computed_field # type: ignore[misc]
|
||||||
def make(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model(self): # noqa - Skip PyCharm inspection
|
def model(self) -> str:
|
||||||
if self.device_info.model is not None:
|
if self.device_info.model is not None:
|
||||||
return str(self.device_info.model)
|
return str(self.device_info.model)
|
||||||
|
|
||||||
@model.setter
|
@computed_field # type: ignore[misc]
|
||||||
def model(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def firmware(self): # noqa - Skip PyCharm inspection
|
def firmware(self) -> str:
|
||||||
if self.device_info.firmware is not None:
|
if self.device_info.firmware is not None:
|
||||||
return str(self.device_info.firmware)
|
return str(self.device_info.firmware)
|
||||||
|
|
||||||
@firmware.setter
|
@computed_field # type: ignore[misc]
|
||||||
def firmware(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def algo(self): # noqa - Skip PyCharm inspection
|
def algo(self) -> str:
|
||||||
if self.device_info.algo is not None:
|
if self.device_info.algo is not None:
|
||||||
return str(self.device_info.algo)
|
return str(self.device_info.algo)
|
||||||
|
|
||||||
@algo.setter
|
|
||||||
def algo(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def keys(self) -> list:
|
def keys(self) -> list:
|
||||||
return [f.name for f in fields(self)]
|
return list(self.model_fields.keys())
|
||||||
|
|
||||||
def asdict(self) -> dict:
|
def asdict(self) -> dict:
|
||||||
return asdict(self, dict_factory=self.dict_factory)
|
return self.model_dump()
|
||||||
|
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
"""Get this dataclass as a dictionary.
|
"""Get this dataclass as a dictionary.
|
||||||
@@ -411,7 +361,7 @@ class MinerData:
|
|||||||
Returns:
|
Returns:
|
||||||
A JSON version of this class.
|
A JSON version of this class.
|
||||||
"""
|
"""
|
||||||
return json.dumps(self.as_dict())
|
return self.model_dump_json()
|
||||||
|
|
||||||
def as_csv(self) -> str:
|
def as_csv(self) -> str:
|
||||||
"""Get this dataclass as CSV.
|
"""Get this dataclass as CSV.
|
||||||
@@ -440,7 +390,7 @@ class MinerData:
|
|||||||
field_data = []
|
field_data = []
|
||||||
|
|
||||||
tags = ["ip", "mac", "model", "hostname"]
|
tags = ["ip", "mac", "model", "hostname"]
|
||||||
for attribute in self:
|
for attribute in self.fields():
|
||||||
if attribute in tags:
|
if attribute in tags:
|
||||||
escaped_data = self.get(attribute, "Unknown").replace(" ", "\\ ")
|
escaped_data = self.get(attribute, "Unknown").replace(" ", "\\ ")
|
||||||
tag_data.append(f"{attribute}={escaped_data}")
|
tag_data.append(f"{attribute}={escaped_data}")
|
||||||
|
|||||||
@@ -13,15 +13,16 @@
|
|||||||
# 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 __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from .hashrate import AlgoHashRate
|
from pydantic import BaseModel, field_serializer
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate import AlgoHashRateType
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class HashBoard(BaseModel):
|
||||||
class HashBoard:
|
|
||||||
"""A Dataclass to standardize hashboard data.
|
"""A Dataclass to standardize hashboard data.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -39,16 +40,21 @@ class HashBoard:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
slot: int = 0
|
slot: int = 0
|
||||||
hashrate: AlgoHashRate = None
|
hashrate: AlgoHashRateType | None = None
|
||||||
temp: int = None
|
temp: float | None = None
|
||||||
chip_temp: int = None
|
chip_temp: float | None = None
|
||||||
chips: int = None
|
chips: int | None = None
|
||||||
expected_chips: int = None
|
expected_chips: int | None = None
|
||||||
serial_number: str = None
|
serial_number: str | None = None
|
||||||
missing: bool = True
|
missing: bool = True
|
||||||
tuned: bool = None
|
tuned: bool | None = None
|
||||||
active: bool = None
|
active: bool | None = None
|
||||||
voltage: float = 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:
|
||||||
|
|||||||
@@ -1,14 +1,31 @@
|
|||||||
from dataclasses import dataclass
|
from pydantic import BaseModel, ConfigDict, field_serializer
|
||||||
|
|
||||||
from pyasic.device.algorithm import MinerAlgo
|
from pyasic.device.algorithm import MinerAlgoType
|
||||||
from pyasic.device.firmware import MinerFirmware
|
from pyasic.device.firmware import MinerFirmware
|
||||||
from pyasic.device.makes import MinerMake
|
from pyasic.device.makes import MinerMake
|
||||||
from pyasic.device.models import MinerModel
|
from pyasic.device.models import MinerModelType
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class DeviceInfo(BaseModel):
|
||||||
class DeviceInfo:
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||||
make: MinerMake = None
|
|
||||||
model: MinerModel = None
|
make: MinerMake | None = None
|
||||||
firmware: MinerFirmware = None
|
model: MinerModelType | None = None
|
||||||
algo: MinerAlgo = None
|
firmware: MinerFirmware | None = None
|
||||||
|
algo: type[MinerAlgoType] | None = None
|
||||||
|
|
||||||
|
@field_serializer("make")
|
||||||
|
def serialize_make(self, make: MinerMake, _info):
|
||||||
|
return str(make)
|
||||||
|
|
||||||
|
@field_serializer("model")
|
||||||
|
def serialize_model(self, model: MinerModelType, _info):
|
||||||
|
return str(model)
|
||||||
|
|
||||||
|
@field_serializer("firmware")
|
||||||
|
def serialize_firmware(self, firmware: MinerFirmware, _info):
|
||||||
|
return str(firmware)
|
||||||
|
|
||||||
|
@field_serializer("algo")
|
||||||
|
def serialize_algo(self, algo: MinerAlgoType, _info):
|
||||||
|
return str(algo)
|
||||||
|
|||||||
@@ -13,12 +13,10 @@
|
|||||||
# 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 pyasic.data.error_codes.base import BaseMinerError
|
||||||
from dataclasses import asdict, dataclass, fields
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class X19Error(BaseMinerError):
|
||||||
class X19Error:
|
|
||||||
"""A Dataclass to handle error codes of X19 miners.
|
"""A Dataclass to handle error codes of X19 miners.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -28,10 +26,3 @@ class X19Error:
|
|||||||
|
|
||||||
error_message: str
|
error_message: str
|
||||||
error_code: int = 0
|
error_code: int = 0
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|||||||
18
pyasic/data/error_codes/base.py
Normal file
18
pyasic/data/error_codes/base.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class BaseMinerError(BaseModel):
|
||||||
|
@classmethod
|
||||||
|
def fields(cls):
|
||||||
|
return list(cls.model_fields.keys())
|
||||||
|
|
||||||
|
def asdict(self) -> dict:
|
||||||
|
return self.model_dump()
|
||||||
|
|
||||||
|
def as_dict(self) -> dict:
|
||||||
|
"""Get this dataclass as a dictionary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A dictionary version of this class.
|
||||||
|
"""
|
||||||
|
return self.asdict()
|
||||||
@@ -14,11 +14,10 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass, fields
|
from pyasic.data.error_codes.base import BaseMinerError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class BraiinsOSError(BaseMinerError):
|
||||||
class BraiinsOSError:
|
|
||||||
"""A Dataclass to handle error codes of BraiinsOS+ miners.
|
"""A Dataclass to handle error codes of BraiinsOS+ miners.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -28,10 +27,3 @@ class BraiinsOSError:
|
|||||||
|
|
||||||
error_message: str
|
error_message: str
|
||||||
error_code: int = 0
|
error_code: int = 0
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|||||||
@@ -14,11 +14,13 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass, field, fields
|
|
||||||
|
from pydantic import computed_field
|
||||||
|
|
||||||
|
from pyasic.data.error_codes.base import BaseMinerError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class InnosiliconError(BaseMinerError):
|
||||||
class InnosiliconError:
|
|
||||||
"""A Dataclass to handle error codes of Innosilicon miners.
|
"""A Dataclass to handle error codes of Innosilicon miners.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -27,25 +29,14 @@ class InnosiliconError:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
error_code: int
|
error_code: int
|
||||||
error_message: str = field(init=False)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def error_message(self): # noqa - Skip PyCharm inspection
|
def error_message(self) -> str: # noqa - Skip PyCharm inspection
|
||||||
if self.error_code in ERROR_CODES:
|
if self.error_code in ERROR_CODES:
|
||||||
return ERROR_CODES[self.error_code]
|
return ERROR_CODES[self.error_code]
|
||||||
return "Unknown error type."
|
return "Unknown error type."
|
||||||
|
|
||||||
@error_message.setter
|
|
||||||
def error_message(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|
||||||
|
|
||||||
ERROR_CODES = {
|
ERROR_CODES = {
|
||||||
21: "The PLUG signal of the hash board is not detected.",
|
21: "The PLUG signal of the hash board is not detected.",
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
# 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 pydantic import computed_field
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass, field, fields
|
from pyasic.data.error_codes.base import BaseMinerError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class WhatsminerError(BaseMinerError):
|
||||||
class WhatsminerError:
|
|
||||||
"""A Dataclass to handle error codes of Whatsminers.
|
"""A Dataclass to handle error codes of Whatsminers.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -27,14 +27,10 @@ class WhatsminerError:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
error_code: int
|
error_code: int
|
||||||
error_message: str = field(init=False)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def error_message(self): # noqa - Skip PyCharm inspection
|
def error_message(self) -> str: # noqa - Skip PyCharm inspection
|
||||||
if len(str(self.error_code)) == 6 and not str(self.error_code)[:1] == "1":
|
if len(str(self.error_code)) == 6 and not str(self.error_code)[:1] == "1":
|
||||||
err_type = int(str(self.error_code)[:2])
|
err_type = int(str(self.error_code)[:2])
|
||||||
err_subtype = int(str(self.error_code)[2:3])
|
err_subtype = int(str(self.error_code)[2:3])
|
||||||
@@ -74,13 +70,6 @@ class WhatsminerError:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return "Unknown error type."
|
return "Unknown error type."
|
||||||
|
|
||||||
@error_message.setter
|
|
||||||
def error_message(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|
||||||
|
|
||||||
ERROR_CODES = {
|
ERROR_CODES = {
|
||||||
1: { # Fan error
|
1: { # Fan error
|
||||||
|
|||||||
@@ -14,12 +14,12 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Fan:
|
class Fan(BaseModel):
|
||||||
"""A Dataclass to standardize fan data.
|
"""A Dataclass to standardize fan data.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
|
|
||||||
from pyasic.data.hashrate.sha256 import SHA256HashRate
|
|
||||||
from pyasic.device.algorithm.sha256 import SHA256Unit
|
|
||||||
|
|
||||||
|
|
||||||
class AlgoHashRate(Enum):
|
|
||||||
SHA256 = SHA256HashRate
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
return self.value(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class HashUnit:
|
|
||||||
SHA256 = SHA256Unit
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
from pyasic.device.algorithm import MinerAlgo
|
|
||||||
from pyasic.device.algorithm.sha256 import SHA256Unit
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class SHA256HashRate:
|
|
||||||
rate: float
|
|
||||||
unit: SHA256Unit = MinerAlgo.SHA256.unit.default
|
|
||||||
|
|
||||||
def __float__(self):
|
|
||||||
return float(self.rate)
|
|
||||||
|
|
||||||
def __int__(self):
|
|
||||||
return int(self.rate)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"{self.rate} {str(self.unit)}"
|
|
||||||
|
|
||||||
def __round__(self, n: int = None):
|
|
||||||
return round(self.rate, n)
|
|
||||||
|
|
||||||
def __add__(self, other: SHA256HashRate | int | float) -> SHA256HashRate:
|
|
||||||
if isinstance(other, SHA256HashRate):
|
|
||||||
return SHA256HashRate(self.rate + other.into(self.unit).rate, self.unit)
|
|
||||||
return SHA256HashRate(self.rate + other, self.unit)
|
|
||||||
|
|
||||||
def __sub__(self, other: SHA256HashRate | int | float) -> SHA256HashRate:
|
|
||||||
if isinstance(other, SHA256HashRate):
|
|
||||||
return SHA256HashRate(self.rate - other.into(self.unit).rate, self.unit)
|
|
||||||
return SHA256HashRate(self.rate - other, self.unit)
|
|
||||||
|
|
||||||
def __truediv__(self, other: SHA256HashRate | int | float):
|
|
||||||
if isinstance(other, SHA256HashRate):
|
|
||||||
return SHA256HashRate(self.rate / other.into(self.unit).rate, self.unit)
|
|
||||||
return SHA256HashRate(self.rate / other, self.unit)
|
|
||||||
|
|
||||||
def __floordiv__(self, other: SHA256HashRate | int | float):
|
|
||||||
if isinstance(other, SHA256HashRate):
|
|
||||||
return SHA256HashRate(self.rate // other.into(self.unit).rate, self.unit)
|
|
||||||
return SHA256HashRate(self.rate // other, self.unit)
|
|
||||||
|
|
||||||
def __mul__(self, other: SHA256HashRate | int | float):
|
|
||||||
if isinstance(other, SHA256HashRate):
|
|
||||||
return SHA256HashRate(self.rate * other.into(self.unit).rate, self.unit)
|
|
||||||
return SHA256HashRate(self.rate * other, self.unit)
|
|
||||||
|
|
||||||
def into(self, other: SHA256Unit) -> SHA256HashRate:
|
|
||||||
return SHA256HashRate(
|
|
||||||
rate=self.rate / (other.value / self.unit.value), unit=other
|
|
||||||
)
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
from dataclasses import dataclass, field
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from pydantic import BaseModel, computed_field, model_serializer
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
|
||||||
class Scheme(Enum):
|
class Scheme(Enum):
|
||||||
STRATUM_V1 = "stratum+tcp"
|
STRATUM_V1 = "stratum+tcp"
|
||||||
@@ -10,13 +12,16 @@ class Scheme(Enum):
|
|||||||
STRATUM_V1_SSL = "stratum+ssl"
|
STRATUM_V1_SSL = "stratum+ssl"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class PoolUrl(BaseModel):
|
||||||
class PoolUrl:
|
|
||||||
scheme: Scheme
|
scheme: Scheme
|
||||||
host: str
|
host: str
|
||||||
port: int
|
port: int
|
||||||
pubkey: Optional[str] = None
|
pubkey: Optional[str] = None
|
||||||
|
|
||||||
|
@model_serializer
|
||||||
|
def serialize(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
if self.scheme == Scheme.STRATUM_V2 and self.pubkey:
|
if self.scheme == Scheme.STRATUM_V2 and self.pubkey:
|
||||||
return f"{self.scheme.value}://{self.host}:{self.port}/{self.pubkey}"
|
return f"{self.scheme.value}://{self.host}:{self.port}/{self.pubkey}"
|
||||||
@@ -24,8 +29,10 @@ class PoolUrl:
|
|||||||
return f"{self.scheme.value}://{self.host}:{self.port}"
|
return f"{self.scheme.value}://{self.host}:{self.port}"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_str(cls, url: str) -> "PoolUrl":
|
def from_str(cls, url: str) -> Self | None:
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlparse(url)
|
||||||
|
if not parsed_url.hostname:
|
||||||
|
return None
|
||||||
if not parsed_url.scheme.strip() == "":
|
if not parsed_url.scheme.strip() == "":
|
||||||
scheme = Scheme(parsed_url.scheme)
|
scheme = Scheme(parsed_url.scheme)
|
||||||
else:
|
else:
|
||||||
@@ -36,8 +43,7 @@ class PoolUrl:
|
|||||||
return cls(scheme=scheme, host=host, port=port, pubkey=pubkey)
|
return cls(scheme=scheme, host=host, port=port, pubkey=pubkey)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class PoolMetrics(BaseModel):
|
||||||
class PoolMetrics:
|
|
||||||
"""A dataclass to standardize pool metrics returned from miners.
|
"""A dataclass to standardize pool metrics returned from miners.
|
||||||
Attributes:
|
Attributes:
|
||||||
|
|
||||||
@@ -54,27 +60,23 @@ class PoolMetrics:
|
|||||||
pool_stale_percent: Percentage of stale shares by the pool.
|
pool_stale_percent: Percentage of stale shares by the pool.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
url: PoolUrl
|
url: PoolUrl | None
|
||||||
accepted: int = None
|
accepted: int | None = None
|
||||||
rejected: int = None
|
rejected: int | None = None
|
||||||
get_failures: int = None
|
get_failures: int | None = None
|
||||||
remote_failures: int = None
|
remote_failures: int | None = None
|
||||||
active: bool = None
|
active: bool | None = None
|
||||||
alive: bool = None
|
alive: bool | None = None
|
||||||
index: int = None
|
index: int | None = None
|
||||||
user: str = None
|
user: str | None = None
|
||||||
pool_rejected_percent: float = field(init=False)
|
|
||||||
pool_stale_percent: float = field(init=False)
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def pool_rejected_percent(self) -> float: # noqa - Skip PyCharm inspection
|
def pool_rejected_percent(self) -> float: # noqa - Skip PyCharm inspection
|
||||||
"""Calculate and return the percentage of rejected shares"""
|
"""Calculate and return the percentage of rejected shares"""
|
||||||
return self._calculate_percentage(self.rejected, self.accepted + self.rejected)
|
return self._calculate_percentage(self.rejected, self.accepted + self.rejected)
|
||||||
|
|
||||||
@pool_rejected_percent.setter
|
@computed_field # type: ignore[misc]
|
||||||
def pool_rejected_percent(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pool_stale_percent(self) -> float: # noqa - Skip PyCharm inspection
|
def pool_stale_percent(self) -> float: # noqa - Skip PyCharm inspection
|
||||||
"""Calculate and return the percentage of stale shares."""
|
"""Calculate and return the percentage of stale shares."""
|
||||||
@@ -82,10 +84,6 @@ class PoolMetrics:
|
|||||||
self.get_failures, self.accepted + self.rejected
|
self.get_failures, self.accepted + self.rejected
|
||||||
)
|
)
|
||||||
|
|
||||||
@pool_stale_percent.setter
|
|
||||||
def pool_stale_percent(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _calculate_percentage(value: int, total: int) -> float:
|
def _calculate_percentage(value: int, total: int) -> float:
|
||||||
"""Calculate the percentage."""
|
"""Calculate the percentage."""
|
||||||
|
|||||||
@@ -1,5 +1,26 @@
|
|||||||
from pyasic.device.algorithm.sha256 import SHA256Algo
|
from .base import MinerAlgoType
|
||||||
|
from .blake256 import Blake256Algo
|
||||||
|
from .eaglesong import EaglesongAlgo
|
||||||
|
from .equihash import EquihashAlgo
|
||||||
|
from .ethash import EtHashAlgo
|
||||||
|
from .handshake import HandshakeAlgo
|
||||||
|
from .hashrate import *
|
||||||
|
from .hashrate.unit import *
|
||||||
|
from .kadena import KadenaAlgo
|
||||||
|
from .kheavyhash import KHeavyHashAlgo
|
||||||
|
from .scrypt import ScryptAlgo
|
||||||
|
from .sha256 import SHA256Algo
|
||||||
|
from .x11 import X11Algo
|
||||||
|
|
||||||
|
|
||||||
class MinerAlgo:
|
class MinerAlgo:
|
||||||
SHA256 = SHA256Algo
|
SHA256 = SHA256Algo
|
||||||
|
SCRYPT = ScryptAlgo
|
||||||
|
KHEAVYHASH = KHeavyHashAlgo
|
||||||
|
KADENA = KadenaAlgo
|
||||||
|
HANDSHAKE = HandshakeAlgo
|
||||||
|
X11 = X11Algo
|
||||||
|
BLAKE256 = Blake256Algo
|
||||||
|
EAGLESONG = EaglesongAlgo
|
||||||
|
ETHASH = EtHashAlgo
|
||||||
|
EQUIHASH = EquihashAlgo
|
||||||
|
|||||||
16
pyasic/device/algorithm/base.py
Normal file
16
pyasic/device/algorithm/base.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .hashrate.base import AlgoHashRateType
|
||||||
|
from .hashrate.unit.base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class MinerAlgoMeta(type):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
def __str__(cls):
|
||||||
|
return cls.name
|
||||||
|
|
||||||
|
|
||||||
|
class MinerAlgoType(metaclass=MinerAlgoMeta):
|
||||||
|
hashrate: type[AlgoHashRateType]
|
||||||
|
unit: type[AlgoHashRateUnitType]
|
||||||
13
pyasic/device/algorithm/blake256.py
Normal file
13
pyasic/device/algorithm/blake256.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import Blake256HashRate
|
||||||
|
from .hashrate.unit import Blake256Unit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class Blake256Algo(MinerAlgoType):
|
||||||
|
hashrate: type[Blake256HashRate] = Blake256HashRate
|
||||||
|
unit: type[Blake256Unit] = Blake256Unit
|
||||||
|
|
||||||
|
name = "Blake256"
|
||||||
13
pyasic/device/algorithm/eaglesong.py
Normal file
13
pyasic/device/algorithm/eaglesong.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import EaglesongHashRate
|
||||||
|
from .hashrate.unit import EaglesongUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class EaglesongAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[EaglesongHashRate] = EaglesongHashRate
|
||||||
|
unit: type[EaglesongUnit] = EaglesongUnit
|
||||||
|
|
||||||
|
name = "Eaglesong"
|
||||||
13
pyasic/device/algorithm/equihash.py
Normal file
13
pyasic/device/algorithm/equihash.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import EquihashHashRate
|
||||||
|
from .hashrate.unit import EquihashUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class EquihashAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[EquihashHashRate] = EquihashHashRate
|
||||||
|
unit: type[EquihashUnit] = EquihashUnit
|
||||||
|
|
||||||
|
name = "Equihash"
|
||||||
12
pyasic/device/algorithm/ethash.py
Normal file
12
pyasic/device/algorithm/ethash.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import EtHashHashRate
|
||||||
|
from .hashrate.unit import EtHashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EtHashAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[EtHashHashRate] = EtHashHashRate
|
||||||
|
unit: type[EtHashUnit] = EtHashUnit
|
||||||
|
|
||||||
|
name = "EtHash"
|
||||||
13
pyasic/device/algorithm/handshake.py
Normal file
13
pyasic/device/algorithm/handshake.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import HandshakeHashRate
|
||||||
|
from .hashrate.unit import HandshakeUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class HandshakeAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[HandshakeHashRate] = HandshakeHashRate
|
||||||
|
unit: type[HandshakeUnit] = HandshakeUnit
|
||||||
|
|
||||||
|
name = "Handshake"
|
||||||
24
pyasic/device/algorithm/hashrate/__init__.py
Normal file
24
pyasic/device/algorithm/hashrate/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from .base import AlgoHashRateType
|
||||||
|
from .blake256 import Blake256HashRate
|
||||||
|
from .eaglesong import EaglesongHashRate
|
||||||
|
from .equihash import EquihashHashRate
|
||||||
|
from .ethash import EtHashHashRate
|
||||||
|
from .handshake import HandshakeHashRate
|
||||||
|
from .kadena import KadenaHashRate
|
||||||
|
from .kheavyhash import KHeavyHashHashRate
|
||||||
|
from .scrypt import ScryptHashRate
|
||||||
|
from .sha256 import SHA256HashRate
|
||||||
|
from .x11 import X11HashRate
|
||||||
|
|
||||||
|
|
||||||
|
class AlgoHashRate:
|
||||||
|
SHA256 = SHA256HashRate
|
||||||
|
SCRYPT = ScryptHashRate
|
||||||
|
KHEAVYHASH = KHeavyHashHashRate
|
||||||
|
KADENA = KadenaHashRate
|
||||||
|
HANDSHAKE = HandshakeHashRate
|
||||||
|
X11 = X11HashRate
|
||||||
|
BLAKE256 = Blake256HashRate
|
||||||
|
EAGLESONG = EaglesongHashRate
|
||||||
|
ETHASH = EtHashHashRate
|
||||||
|
EQUIHASH = EquihashHashRate
|
||||||
71
pyasic/device/algorithm/hashrate/base.py
Normal file
71
pyasic/device/algorithm/hashrate/base.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from .unit.base import AlgoHashRateUnitType, GenericUnit
|
||||||
|
|
||||||
|
|
||||||
|
class AlgoHashRateType(BaseModel, ABC):
|
||||||
|
unit: AlgoHashRateUnitType
|
||||||
|
rate: float
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def into(self, other: "AlgoHashRateUnitType"):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __float__(self):
|
||||||
|
return float(self.rate)
|
||||||
|
|
||||||
|
def __int__(self):
|
||||||
|
return int(self.rate)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.rate} {str(self.unit)}"
|
||||||
|
|
||||||
|
def __round__(self, n: int = None):
|
||||||
|
return round(self.rate, n)
|
||||||
|
|
||||||
|
def __add__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, AlgoHashRateType):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate + other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate + other, unit=self.unit)
|
||||||
|
|
||||||
|
def __sub__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, AlgoHashRateType):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate - other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate - other, unit=self.unit)
|
||||||
|
|
||||||
|
def __truediv__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, AlgoHashRateType):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate / other, unit=self.unit)
|
||||||
|
|
||||||
|
def __floordiv__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, AlgoHashRateType):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate // other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate // other, unit=self.unit)
|
||||||
|
|
||||||
|
def __mul__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, AlgoHashRateType):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate * other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate * other, unit=self.unit)
|
||||||
|
|
||||||
|
|
||||||
|
class GenericHashrate(AlgoHashRateType):
|
||||||
|
def into(self, other: GenericUnit):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/blake256.py
Normal file
18
pyasic/device/algorithm/hashrate/blake256.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.blake256 import Blake256Unit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class Blake256HashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: Blake256Unit = HashUnit.BLAKE256.default
|
||||||
|
|
||||||
|
def into(self, other: Blake256Unit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/eaglesong.py
Normal file
18
pyasic/device/algorithm/hashrate/eaglesong.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.eaglesong import EaglesongUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EaglesongHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: EaglesongUnit = HashUnit.EAGLESONG.default
|
||||||
|
|
||||||
|
def into(self, other: EaglesongUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/equihash.py
Normal file
18
pyasic/device/algorithm/hashrate/equihash.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.equihash import EquihashUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EquihashHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: EquihashUnit = HashUnit.ETHASH.default
|
||||||
|
|
||||||
|
def into(self, other: EquihashUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/ethash.py
Normal file
18
pyasic/device/algorithm/hashrate/ethash.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.ethash import EtHashUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EtHashHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: EtHashUnit = HashUnit.ETHASH.default
|
||||||
|
|
||||||
|
def into(self, other: EtHashUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/handshake.py
Normal file
18
pyasic/device/algorithm/hashrate/handshake.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.handshake import HandshakeUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class HandshakeHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: HandshakeUnit = HashUnit.HANDSHAKE.default
|
||||||
|
|
||||||
|
def into(self, other: HandshakeUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/kadena.py
Normal file
18
pyasic/device/algorithm/hashrate/kadena.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.kadena import KadenaUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class KadenaHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: KadenaUnit = HashUnit.KADENA.default
|
||||||
|
|
||||||
|
def into(self, other: KadenaUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/kheavyhash.py
Normal file
18
pyasic/device/algorithm/hashrate/kheavyhash.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.kheavyhash import KHeavyHashUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class KHeavyHashHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: KHeavyHashUnit = HashUnit.KHEAVYHASH.default
|
||||||
|
|
||||||
|
def into(self, other: KHeavyHashUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/scrypt.py
Normal file
18
pyasic/device/algorithm/hashrate/scrypt.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.scrypt import ScryptUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class ScryptHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: ScryptUnit = HashUnit.SCRYPT.default
|
||||||
|
|
||||||
|
def into(self, other: ScryptUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/sha256.py
Normal file
18
pyasic/device/algorithm/hashrate/sha256.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.sha256 import SHA256Unit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class SHA256HashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: SHA256Unit = HashUnit.SHA256.default
|
||||||
|
|
||||||
|
def into(self, other: SHA256Unit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
23
pyasic/device/algorithm/hashrate/unit/__init__.py
Normal file
23
pyasic/device/algorithm/hashrate/unit/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from .blake256 import Blake256Unit
|
||||||
|
from .eaglesong import EaglesongUnit
|
||||||
|
from .equihash import EquihashUnit
|
||||||
|
from .ethash import EtHashUnit
|
||||||
|
from .handshake import HandshakeUnit
|
||||||
|
from .kadena import KadenaUnit
|
||||||
|
from .kheavyhash import KHeavyHashUnit
|
||||||
|
from .scrypt import ScryptUnit
|
||||||
|
from .sha256 import SHA256Unit
|
||||||
|
from .x11 import X11Unit
|
||||||
|
|
||||||
|
|
||||||
|
class HashUnit:
|
||||||
|
SHA256 = SHA256Unit
|
||||||
|
SCRYPT = ScryptUnit
|
||||||
|
KHEAVYHASH = KHeavyHashUnit
|
||||||
|
KADENA = KadenaUnit
|
||||||
|
HANDSHAKE = HandshakeUnit
|
||||||
|
X11 = X11Unit
|
||||||
|
BLAKE256 = Blake256Unit
|
||||||
|
EAGLESONG = EaglesongUnit
|
||||||
|
ETHASH = EtHashUnit
|
||||||
|
EQUIHASH = EquihashUnit
|
||||||
68
pyasic/device/algorithm/hashrate/unit/base.py
Normal file
68
pyasic/device/algorithm/hashrate/unit/base.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
|
||||||
|
class AlgoHashRateUnitType(IntEnum):
|
||||||
|
H: int
|
||||||
|
KH: int
|
||||||
|
MH: int
|
||||||
|
GH: int
|
||||||
|
TH: int
|
||||||
|
PH: int
|
||||||
|
EH: int
|
||||||
|
ZH: int
|
||||||
|
|
||||||
|
default: int
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.value == self.H:
|
||||||
|
return "H/s"
|
||||||
|
if self.value == self.KH:
|
||||||
|
return "KH/s"
|
||||||
|
if self.value == self.MH:
|
||||||
|
return "MH/s"
|
||||||
|
if self.value == self.GH:
|
||||||
|
return "GH/s"
|
||||||
|
if self.value == self.TH:
|
||||||
|
return "TH/s"
|
||||||
|
if self.value == self.PH:
|
||||||
|
return "PH/s"
|
||||||
|
if self.value == self.EH:
|
||||||
|
return "EH/s"
|
||||||
|
if self.value == self.ZH:
|
||||||
|
return "ZH/s"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_str(cls, value: str):
|
||||||
|
if value == "H":
|
||||||
|
return cls.H
|
||||||
|
elif value == "KH":
|
||||||
|
return cls.KH
|
||||||
|
elif value == "MH":
|
||||||
|
return cls.MH
|
||||||
|
elif value == "GH":
|
||||||
|
return cls.GH
|
||||||
|
elif value == "TH":
|
||||||
|
return cls.TH
|
||||||
|
elif value == "PH":
|
||||||
|
return cls.PH
|
||||||
|
elif value == "EH":
|
||||||
|
return cls.EH
|
||||||
|
elif value == "ZH":
|
||||||
|
return cls.ZH
|
||||||
|
return cls.default
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 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
|
||||||
16
pyasic/device/algorithm/hashrate/unit/blake256.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/blake256.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class Blake256Unit(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 = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/eaglesong.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/eaglesong.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class EaglesongUnit(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 = TH
|
||||||
34
pyasic/device/algorithm/hashrate/unit/equihash.py
Normal file
34
pyasic/device/algorithm/hashrate/unit/equihash.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class EquihashUnit(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 = KH
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.value == self.H:
|
||||||
|
return "Sol/s"
|
||||||
|
if self.value == self.KH:
|
||||||
|
return "KSol/s"
|
||||||
|
if self.value == self.MH:
|
||||||
|
return "MSol/s"
|
||||||
|
if self.value == self.GH:
|
||||||
|
return "GSol/s"
|
||||||
|
if self.value == self.TH:
|
||||||
|
return "TSol/s"
|
||||||
|
if self.value == self.PH:
|
||||||
|
return "PSol/s"
|
||||||
|
if self.value == self.EH:
|
||||||
|
return "ESol/s"
|
||||||
|
if self.value == self.ZH:
|
||||||
|
return "ZSol/s"
|
||||||
16
pyasic/device/algorithm/hashrate/unit/ethash.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/ethash.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class EtHashUnit(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 = MH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/handshake.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/handshake.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class HandshakeUnit(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 = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/kadena.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/kadena.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class KadenaUnit(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 = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/kheavyhash.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/kheavyhash.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class KHeavyHashUnit(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 = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/scrypt.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/scrypt.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class ScryptUnit(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 = GH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/sha256.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/sha256.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class SHA256Unit(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 = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/x11.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/x11.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class X11Unit(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 = GH
|
||||||
18
pyasic/device/algorithm/hashrate/x11.py
Normal file
18
pyasic/device/algorithm/hashrate/x11.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.x11 import X11Unit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class X11HashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: X11Unit = HashUnit.X11.default
|
||||||
|
|
||||||
|
def into(self, other: X11Unit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
13
pyasic/device/algorithm/kadena.py
Normal file
13
pyasic/device/algorithm/kadena.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import KadenaHashRate
|
||||||
|
from .hashrate.unit import KadenaUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class KadenaAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[KadenaHashRate] = KadenaHashRate
|
||||||
|
unit: type[KadenaUnit] = KadenaUnit
|
||||||
|
|
||||||
|
name = "Kadena"
|
||||||
13
pyasic/device/algorithm/kheavyhash.py
Normal file
13
pyasic/device/algorithm/kheavyhash.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import KHeavyHashHashRate
|
||||||
|
from .hashrate.unit import KHeavyHashUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class KHeavyHashAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[KHeavyHashHashRate] = KHeavyHashHashRate
|
||||||
|
unit: type[KHeavyHashUnit] = KHeavyHashUnit
|
||||||
|
|
||||||
|
name = "KHeavyHash"
|
||||||
12
pyasic/device/algorithm/scrypt.py
Normal file
12
pyasic/device/algorithm/scrypt.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import ScryptHashRate
|
||||||
|
from .hashrate.unit import ScryptUnit
|
||||||
|
|
||||||
|
|
||||||
|
class ScryptAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[ScryptHashRate] = ScryptHashRate
|
||||||
|
unit: type[ScryptUnit] = ScryptUnit
|
||||||
|
|
||||||
|
name = "Scrypt"
|
||||||
@@ -1,68 +1,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from enum import IntEnum
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import SHA256HashRate
|
||||||
|
from .hashrate.unit import SHA256Unit
|
||||||
class SHA256Unit(IntEnum):
|
|
||||||
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 = TH
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self.value == self.H:
|
|
||||||
return "H/s"
|
|
||||||
if self.value == self.KH:
|
|
||||||
return "KH/s"
|
|
||||||
if self.value == self.MH:
|
|
||||||
return "MH/s"
|
|
||||||
if self.value == self.GH:
|
|
||||||
return "GH/s"
|
|
||||||
if self.value == self.TH:
|
|
||||||
return "TH/s"
|
|
||||||
if self.value == self.PH:
|
|
||||||
return "PH/s"
|
|
||||||
if self.value == self.EH:
|
|
||||||
return "EH/s"
|
|
||||||
if self.value == self.ZH:
|
|
||||||
return "ZH/s"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_str(cls, value: str):
|
|
||||||
if value == "H":
|
|
||||||
return cls.H
|
|
||||||
elif value == "KH":
|
|
||||||
return cls.KH
|
|
||||||
elif value == "MH":
|
|
||||||
return cls.MH
|
|
||||||
elif value == "GH":
|
|
||||||
return cls.GH
|
|
||||||
elif value == "TH":
|
|
||||||
return cls.TH
|
|
||||||
elif value == "PH":
|
|
||||||
return cls.PH
|
|
||||||
elif value == "EH":
|
|
||||||
return cls.EH
|
|
||||||
elif value == "ZH":
|
|
||||||
return cls.ZH
|
|
||||||
return cls.default
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
|
|
||||||
# make this json serializable
|
# make this json serializable
|
||||||
class _SHA256Algo(str):
|
class SHA256Algo(MinerAlgoType):
|
||||||
unit = SHA256Unit
|
hashrate: type[SHA256HashRate] = SHA256HashRate
|
||||||
|
unit: type[SHA256Unit] = SHA256Unit
|
||||||
|
|
||||||
def __repr__(self):
|
name = "SHA256"
|
||||||
return "SHA256Algo"
|
|
||||||
|
|
||||||
|
|
||||||
SHA256Algo = _SHA256Algo("SHA256")
|
|
||||||
|
|||||||
13
pyasic/device/algorithm/x11.py
Normal file
13
pyasic/device/algorithm/x11.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import X11HashRate
|
||||||
|
from .hashrate.unit import X11Unit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class X11Algo(MinerAlgoType):
|
||||||
|
hashrate: type[X11HashRate] = X11HashRate
|
||||||
|
unit: type[X11Unit] = X11Unit
|
||||||
|
|
||||||
|
name = "X11"
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class AntminerModels(str, Enum):
|
class MinerModelType(str, Enum):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AntminerModels(MinerModelType):
|
||||||
D3 = "D3"
|
D3 = "D3"
|
||||||
HS3 = "HS3"
|
HS3 = "HS3"
|
||||||
L3Plus = "L3+"
|
L3Plus = "L3+"
|
||||||
@@ -11,12 +15,14 @@ class AntminerModels(str, Enum):
|
|||||||
KS5 = "KS5"
|
KS5 = "KS5"
|
||||||
L7 = "L7"
|
L7 = "L7"
|
||||||
K7 = "K7"
|
K7 = "K7"
|
||||||
|
D7 = "D7"
|
||||||
E9Pro = "E9Pro"
|
E9Pro = "E9Pro"
|
||||||
S9 = "S9"
|
S9 = "S9"
|
||||||
S9i = "S9i"
|
S9i = "S9i"
|
||||||
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"
|
||||||
@@ -57,7 +63,7 @@ class AntminerModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class WhatsminerModels(str, Enum):
|
class WhatsminerModels(MinerModelType):
|
||||||
M20V10 = "M20 V10"
|
M20V10 = "M20 V10"
|
||||||
M20SV10 = "M20S V10"
|
M20SV10 = "M20S V10"
|
||||||
M20SV20 = "M20S V20"
|
M20SV20 = "M20S V20"
|
||||||
@@ -278,7 +284,7 @@ class WhatsminerModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class AvalonminerModels(str, Enum):
|
class AvalonminerModels(MinerModelType):
|
||||||
Avalon721 = "Avalon 721"
|
Avalon721 = "Avalon 721"
|
||||||
Avalon741 = "Avalon 741"
|
Avalon741 = "Avalon 741"
|
||||||
Avalon761 = "Avalon 761"
|
Avalon761 = "Avalon 761"
|
||||||
@@ -290,6 +296,7 @@ class AvalonminerModels(str, Enum):
|
|||||||
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"
|
||||||
|
|
||||||
@@ -297,7 +304,7 @@ class AvalonminerModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class InnosiliconModels(str, Enum):
|
class InnosiliconModels(MinerModelType):
|
||||||
T3HPlus = "T3H+"
|
T3HPlus = "T3H+"
|
||||||
A10X = "A10X"
|
A10X = "A10X"
|
||||||
A11 = "A11"
|
A11 = "A11"
|
||||||
@@ -307,7 +314,7 @@ class InnosiliconModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class GoldshellModels(str, Enum):
|
class GoldshellModels(MinerModelType):
|
||||||
CK5 = "CK5"
|
CK5 = "CK5"
|
||||||
HS5 = "HS5"
|
HS5 = "HS5"
|
||||||
KD5 = "KD5"
|
KD5 = "KD5"
|
||||||
@@ -319,7 +326,7 @@ class GoldshellModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class ePICModels(str, Enum):
|
class ePICModels(MinerModelType):
|
||||||
BM520i = "BlockMiner 520i"
|
BM520i = "BlockMiner 520i"
|
||||||
BM720i = "BlockMiner 720i"
|
BM720i = "BlockMiner 720i"
|
||||||
|
|
||||||
@@ -327,7 +334,7 @@ class ePICModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class AuradineModels(str, Enum):
|
class AuradineModels(MinerModelType):
|
||||||
AT1500 = "AT1500"
|
AT1500 = "AT1500"
|
||||||
AT2860 = "AT2860"
|
AT2860 = "AT2860"
|
||||||
AT2880 = "AT2880"
|
AT2880 = "AT2880"
|
||||||
@@ -340,16 +347,17 @@ class AuradineModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class BitAxeModels(str, Enum):
|
class BitAxeModels(MinerModelType):
|
||||||
BM1366 = "Ultra"
|
BM1366 = "Ultra"
|
||||||
BM1368 = "Supra"
|
BM1368 = "Supra"
|
||||||
BM1397 = "Max"
|
BM1397 = "Max"
|
||||||
|
BM1370 = "Gamma"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class IceRiverModels(str, Enum):
|
class IceRiverModels(MinerModelType):
|
||||||
KS0 = "KS0"
|
KS0 = "KS0"
|
||||||
KS1 = "KS1"
|
KS1 = "KS1"
|
||||||
KS2 = "KS2"
|
KS2 = "KS2"
|
||||||
@@ -364,7 +372,7 @@ class IceRiverModels(str, Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class HammerModels(str, Enum):
|
class HammerModels(MinerModelType):
|
||||||
D10 = "D10"
|
D10 = "D10"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
21
pyasic/miners/antminer/bmminer/X7/D7.py
Normal file
21
pyasic/miners/antminer/bmminer/X7/D7.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 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 D7
|
||||||
|
|
||||||
|
|
||||||
|
class BMMinerD7(AntminerModern, D7):
|
||||||
|
pass
|
||||||
@@ -13,5 +13,6 @@
|
|||||||
# 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 .D7 import BMMinerD7
|
||||||
from .K7 import BMMinerK7
|
from .K7 import BMMinerK7
|
||||||
from .L7 import BMMinerL7
|
from .L7 import BMMinerL7
|
||||||
|
|||||||
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
|
||||||
|
|||||||
99
pyasic/miners/antminer/hiveon/X19/S19.py
Normal file
99
pyasic/miners/antminer/hiveon/X19/S19.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 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 HiveonModern
|
||||||
|
from pyasic.miners.device.models import (
|
||||||
|
S19,
|
||||||
|
S19L,
|
||||||
|
S19XP,
|
||||||
|
S19a,
|
||||||
|
S19aPro,
|
||||||
|
S19Hydro,
|
||||||
|
S19i,
|
||||||
|
S19j,
|
||||||
|
S19jNoPIC,
|
||||||
|
S19jPro,
|
||||||
|
S19KPro,
|
||||||
|
S19Plus,
|
||||||
|
S19Pro,
|
||||||
|
S19ProHydro,
|
||||||
|
S19ProPlus,
|
||||||
|
S19ProPlusHydro,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19(HiveonModern, S19):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19Plus(HiveonModern, S19Plus):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19i(HiveonModern, S19i):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19Pro(HiveonModern, S19Pro):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19ProPlus(HiveonModern, S19ProPlus):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19XP(HiveonModern, S19XP):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19a(HiveonModern, S19a):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19aPro(HiveonModern, S19aPro):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19j(HiveonModern, S19j):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19jNoPIC(HiveonModern, S19jNoPIC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19jPro(HiveonModern, S19jPro):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19L(HiveonModern, S19L):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19ProHydro(HiveonModern, S19ProHydro):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19Hydro(HiveonModern, S19Hydro):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19ProPlusHydro(HiveonModern, S19ProPlusHydro):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonS19KPro(HiveonModern, S19KPro):
|
||||||
|
pass
|
||||||
22
pyasic/miners/antminer/hiveon/X19/T19.py
Normal file
22
pyasic/miners/antminer/hiveon/X19/T19.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 HiveonModern
|
||||||
|
from pyasic.miners.device.models import T19
|
||||||
|
|
||||||
|
|
||||||
|
class HiveonT19(HiveonModern, T19):
|
||||||
|
pass
|
||||||
35
pyasic/miners/antminer/hiveon/X19/__init__.py
Normal file
35
pyasic/miners/antminer/hiveon/X19/__init__.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 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 .S19 import (
|
||||||
|
HiveonS19,
|
||||||
|
HiveonS19a,
|
||||||
|
HiveonS19aPro,
|
||||||
|
HiveonS19Hydro,
|
||||||
|
HiveonS19i,
|
||||||
|
HiveonS19j,
|
||||||
|
HiveonS19jNoPIC,
|
||||||
|
HiveonS19jPro,
|
||||||
|
HiveonS19KPro,
|
||||||
|
HiveonS19L,
|
||||||
|
HiveonS19Plus,
|
||||||
|
HiveonS19Pro,
|
||||||
|
HiveonS19ProHydro,
|
||||||
|
HiveonS19ProPlus,
|
||||||
|
HiveonS19ProPlusHydro,
|
||||||
|
HiveonS19XP,
|
||||||
|
)
|
||||||
|
from .T19 import HiveonT19
|
||||||
@@ -18,9 +18,10 @@ from typing import List, Optional
|
|||||||
|
|
||||||
import asyncssh
|
import asyncssh
|
||||||
|
|
||||||
from pyasic.data import AlgoHashRate, HashBoard, HashUnit
|
from pyasic.data import HashBoard
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate, HashUnit
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.backends import Hiveon
|
from pyasic.miners.backends import HiveonOld
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||||
from pyasic.miners.device.models import T9
|
from pyasic.miners.device.models import T9
|
||||||
|
|
||||||
@@ -62,28 +63,21 @@ HIVEON_T9_DATA_LOC = DataLocations(
|
|||||||
"_get_uptime",
|
"_get_uptime",
|
||||||
[RPCAPICommand("rpc_stats", "stats")],
|
[RPCAPICommand("rpc_stats", "stats")],
|
||||||
),
|
),
|
||||||
|
str(DataOptions.POOLS): DataFunction(
|
||||||
|
"_get_pools",
|
||||||
|
[RPCAPICommand("rpc_pools", "pools")],
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class HiveonT9(Hiveon, T9):
|
class HiveonT9(HiveonOld, T9):
|
||||||
data_locations = HIVEON_T9_DATA_LOC
|
data_locations = HIVEON_T9_DATA_LOC
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
async def get_mac(self):
|
|
||||||
try:
|
|
||||||
mac = (
|
|
||||||
(await self.send_ssh_command("cat /sys/class/net/eth0/address"))
|
|
||||||
.strip()
|
|
||||||
.upper()
|
|
||||||
)
|
|
||||||
return mac
|
|
||||||
except (TypeError, ValueError, asyncssh.Error, OSError, AttributeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_hashboards(self, rpc_stats: dict = None) -> List[HashBoard]:
|
async def _get_hashboards(self, rpc_stats: dict = None) -> List[HashBoard]:
|
||||||
hashboards = [
|
hashboards = [
|
||||||
HashBoard(slot=board, expected_chips=self.expected_chips)
|
HashBoard(slot=board, expected_chips=self.expected_chips)
|
||||||
@@ -122,29 +116,12 @@ class HiveonT9(Hiveon, T9):
|
|||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
pass
|
pass
|
||||||
hashboards[board].hashrate = AlgoHashRate.SHA256(
|
hashboards[board].hashrate = AlgoHashRate.SHA256(
|
||||||
hashrate, HashUnit.SHA256.GH
|
rate=float(hashrate), unit=HashUnit.SHA256.GH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
hashboards[board].chips = chips
|
hashboards[board].chips = chips
|
||||||
|
|
||||||
return hashboards
|
return hashboards
|
||||||
|
|
||||||
async def _get_wattage(self, rpc_stats: dict = None) -> Optional[int]:
|
|
||||||
if not rpc_stats:
|
|
||||||
try:
|
|
||||||
rpc_stats = await self.rpc.stats()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if rpc_stats:
|
|
||||||
boards = rpc_stats.get("STATS")
|
|
||||||
try:
|
|
||||||
wattage_raw = boards[1]["chain_power"]
|
|
||||||
except (KeyError, IndexError):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
# parse wattage position out of raw data
|
|
||||||
return round(float(wattage_raw.split(" ")[0]))
|
|
||||||
|
|
||||||
async def _get_env_temp(self, rpc_stats: dict = None) -> Optional[float]:
|
async def _get_env_temp(self, rpc_stats: dict = None) -> Optional[float]:
|
||||||
env_temp_list = []
|
env_temp_list = []
|
||||||
board_map = {
|
board_map = {
|
||||||
@@ -168,4 +145,4 @@ class HiveonT9(Hiveon, T9):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if not env_temp_list == []:
|
if not env_temp_list == []:
|
||||||
return round(float(sum(env_temp_list) / len(env_temp_list)), 2)
|
return round(sum(env_temp_list) / len(env_temp_list))
|
||||||
|
|||||||
@@ -15,3 +15,4 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from .X9 import *
|
from .X9 import *
|
||||||
|
from .X19 import *
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from .cgminer import CGMiner
|
|||||||
from .epic import ePIC
|
from .epic import ePIC
|
||||||
from .goldshell import GoldshellMiner
|
from .goldshell import GoldshellMiner
|
||||||
from .hammer import BlackMiner
|
from .hammer import BlackMiner
|
||||||
from .hiveon import Hiveon
|
from .hiveon import HiveonModern, HiveonOld
|
||||||
from .iceriver import IceRiver
|
from .iceriver import IceRiver
|
||||||
from .innosilicon import Innosilicon
|
from .innosilicon import Innosilicon
|
||||||
from .luxminer import LUXMiner
|
from .luxminer import LUXMiner
|
||||||
|
|||||||
@@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Union
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig, MiningModeConfig
|
from pyasic.config import MinerConfig, MiningModeConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.backends.bmminer import BMMiner
|
from pyasic.miners.backends.bmminer import BMMiner
|
||||||
from pyasic.miners.backends.cgminer import CGMiner
|
from pyasic.miners.backends.cgminer import CGMiner
|
||||||
@@ -183,13 +184,13 @@ class AntminerModern(BMMiner):
|
|||||||
|
|
||||||
async def stop_mining(self) -> bool:
|
async def stop_mining(self) -> bool:
|
||||||
cfg = await self.get_config()
|
cfg = await self.get_config()
|
||||||
cfg.miner_mode = MiningModeConfig.sleep
|
cfg.miner_mode = MiningModeConfig.sleep()
|
||||||
await self.send_config(cfg)
|
await self.send_config(cfg)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def resume_mining(self) -> bool:
|
async def resume_mining(self) -> bool:
|
||||||
cfg = await self.get_config()
|
cfg = await self.get_config()
|
||||||
cfg.miner_mode = MiningModeConfig.normal
|
cfg.miner_mode = MiningModeConfig.normal()
|
||||||
await self.send_config(cfg)
|
await self.send_config(cfg)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -239,7 +240,7 @@ class AntminerModern(BMMiner):
|
|||||||
for item in web_summary["SUMMARY"][0]["status"]:
|
for item in web_summary["SUMMARY"][0]["status"]:
|
||||||
try:
|
try:
|
||||||
if not item["status"] == "s":
|
if not item["status"] == "s":
|
||||||
errors.append(X19Error(item["msg"]))
|
errors.append(X19Error(error_message=item["msg"]))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
continue
|
continue
|
||||||
except LookupError:
|
except LookupError:
|
||||||
@@ -248,7 +249,7 @@ class AntminerModern(BMMiner):
|
|||||||
|
|
||||||
async def _get_hashboards(self) -> List[HashBoard]:
|
async def _get_hashboards(self) -> List[HashBoard]:
|
||||||
hashboards = [
|
hashboards = [
|
||||||
HashBoard(idx, expected_chips=self.expected_chips)
|
HashBoard(slot=idx, expected_chips=self.expected_chips)
|
||||||
for idx in range(self.expected_hashboards)
|
for idx in range(self.expected_hashboards)
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -260,8 +261,8 @@ class AntminerModern(BMMiner):
|
|||||||
if rpc_stats is not None:
|
if rpc_stats is not None:
|
||||||
try:
|
try:
|
||||||
for board in rpc_stats["STATS"][0]["chain"]:
|
for board in rpc_stats["STATS"][0]["chain"]:
|
||||||
hashboards[board["index"]].hashrate = AlgoHashRate.SHA256(
|
hashboards[board["index"]].hashrate = self.algo.hashrate(
|
||||||
board["rate_real"], HashUnit.SHA256.GH
|
rate=board["rate_real"], unit=self.algo.unit.GH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
hashboards[board["index"]].chips = board["asic_num"]
|
hashboards[board["index"]].chips = board["asic_num"]
|
||||||
board_temp_data = list(
|
board_temp_data = list(
|
||||||
@@ -317,8 +318,8 @@ class AntminerModern(BMMiner):
|
|||||||
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
|
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
rate_unit = "GH"
|
rate_unit = "GH"
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
rate=float(expected_rate), unit=self.algo.unit.from_str(rate_unit)
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
@@ -597,44 +598,52 @@ class AntminerOld(CGMiner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if rpc_stats is not None:
|
if rpc_stats is not None:
|
||||||
board_offset = -1
|
try:
|
||||||
boards = rpc_stats["STATS"]
|
board_offset = -1
|
||||||
if len(boards) > 1:
|
boards = rpc_stats["STATS"]
|
||||||
for board_num in range(1, 16, 5):
|
if len(boards) > 1:
|
||||||
for _b_num in range(5):
|
for board_num in range(1, 16, 5):
|
||||||
b = boards[1].get(f"chain_acn{board_num + _b_num}")
|
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:
|
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(board_offset, board_offset + self.expected_hashboards):
|
for i in range(
|
||||||
hashboard = HashBoard(
|
board_offset, board_offset + self.expected_hashboards
|
||||||
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 = self.algo.hashrate(
|
||||||
float(hashrate), HashUnit.SHA256.GH
|
rate=float(hashrate), unit=self.algo.unit.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:
|
||||||
|
return [
|
||||||
|
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||||
|
for i in range(self.expected_hashboards)
|
||||||
|
]
|
||||||
|
|
||||||
return hashboards
|
return hashboards
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ from enum import Enum
|
|||||||
from typing import List, Optional
|
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 Fan, HashBoard
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.data import (
|
from pyasic.miners.data import (
|
||||||
DataFunction,
|
DataFunction,
|
||||||
@@ -292,8 +293,9 @@ class Auradine(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_summary["SUMMARY"][0]["MHS 5s"], HashUnit.SHA256.MH
|
rate=float(rpc_summary["SUMMARY"][0]["MHS 5s"]),
|
||||||
|
unit=self.algo.unit.MH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
@@ -321,10 +323,10 @@ class Auradine(StockFirmware):
|
|||||||
try:
|
try:
|
||||||
for board in rpc_devs["DEVS"]:
|
for board in rpc_devs["DEVS"]:
|
||||||
b_id = board["ID"] - 1
|
b_id = board["ID"] - 1
|
||||||
hashboards[b_id].hashrate = AlgoHashRate.SHA256(
|
hashboards[b_id].hashrate = self.algo.hashrate(
|
||||||
board["MHS 5s"], HashUnit.SHA256.MH
|
rate=float(board["MHS 5s"]), unit=self.algo.unit.MH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
hashboards[b_id].temp = round(float(float(board["Temperature"])), 2)
|
hashboards[b_id].temp = round(float(board["Temperature"]))
|
||||||
hashboards[b_id].missing = False
|
hashboards[b_id].missing = False
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
@@ -390,7 +392,7 @@ class Auradine(StockFirmware):
|
|||||||
if web_fan is not None:
|
if web_fan is not None:
|
||||||
try:
|
try:
|
||||||
for fan in web_fan["Fan"]:
|
for fan in web_fan["Fan"]:
|
||||||
fans.append(Fan(round(fan["Speed"])))
|
fans.append(Fan(speed=round(fan["Speed"])))
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
return fans
|
return fans
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
import re
|
import re
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.backends.cgminer import CGMiner
|
from pyasic.miners.backends.cgminer import CGMiner
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||||
@@ -183,8 +184,8 @@ class AvalonMiner(CGMiner):
|
|||||||
|
|
||||||
if rpc_devs is not None:
|
if rpc_devs is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_devs["DEVS"][0]["MHS 1m"], HashUnit.SHA256.MH
|
rate=float(rpc_devs["DEVS"][0]["MHS 1m"]), unit=self.algo.unit.MH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (KeyError, IndexError, ValueError, TypeError):
|
except (KeyError, IndexError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
@@ -216,8 +217,8 @@ class AvalonMiner(CGMiner):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
board_hr = parsed_stats["MGHS"][board]
|
board_hr = parsed_stats["MGHS"][board]
|
||||||
hashboards[board].hashrate = AlgoHashRate.SHA256(
|
hashboards[board].hashrate = self.algo.hashrate(
|
||||||
float(board_hr), HashUnit.SHA256.GH
|
rate=float(board_hr), unit=self.algo.unit.GH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
@@ -252,8 +253,8 @@ class AvalonMiner(CGMiner):
|
|||||||
try:
|
try:
|
||||||
unparsed_stats = rpc_stats["STATS"][0]["MM ID0"]
|
unparsed_stats = rpc_stats["STATS"][0]["MM ID0"]
|
||||||
parsed_stats = self.parse_stats(unparsed_stats)
|
parsed_stats = self.parse_stats(unparsed_stats)
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
float(parsed_stats["GHSmm"][0]), HashUnit.SHA256.GH
|
rate=float(parsed_stats["GHSmm"][0]), unit=self.algo.unit.GH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (IndexError, KeyError, ValueError, TypeError):
|
except (IndexError, KeyError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
from typing import List, Optional
|
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 Fan, HashBoard
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
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
|
||||||
@@ -120,8 +121,9 @@ class BFGMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_summary["SUMMARY"][0]["MHS 20s"], HashUnit.SHA256.MH
|
rate=float(rpc_summary["SUMMARY"][0]["MHS 20s"]),
|
||||||
|
unit=self.algo.unit.MH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
@@ -166,8 +168,8 @@ class BFGMiner(StockFirmware):
|
|||||||
|
|
||||||
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 = self.algo.hashrate(
|
||||||
hashrate, HashUnit.SHA256.GH
|
rate=float(hashrate), unit=self.algo.unit.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}")
|
||||||
@@ -259,8 +261,8 @@ class BFGMiner(StockFirmware):
|
|||||||
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
|
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
rate_unit = "GH"
|
rate_unit = "GH"
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
rate=float(expected_rate), unit=self.algo.unit.from_str(rate_unit)
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic import APIError, MinerConfig
|
from pyasic import APIError, MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.device import MinerFirmware
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
|
from pyasic.device.firmware import MinerFirmware
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import BaseMiner
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||||
from pyasic.web.bitaxe import BitAxeWebAPI
|
from pyasic.web.bitaxe import BitAxeWebAPI
|
||||||
@@ -93,8 +94,8 @@ class BitAxe(BaseMiner):
|
|||||||
|
|
||||||
if web_system_info is not None:
|
if web_system_info is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
web_system_info["hashRate"], HashUnit.SHA256.GH
|
rate=float(web_system_info["hashRate"]), unit=self.algo.unit.GH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@@ -123,8 +124,9 @@ class BitAxe(BaseMiner):
|
|||||||
try:
|
try:
|
||||||
return [
|
return [
|
||||||
HashBoard(
|
HashBoard(
|
||||||
hashrate=AlgoHashRate.SHA256(
|
hashrate=self.algo.hashrate(
|
||||||
web_system_info["hashRate"], HashUnit.SHA256.GH
|
rate=float(web_system_info["hashRate"]),
|
||||||
|
unit=self.algo.unit.GH,
|
||||||
).into(self.algo.unit.default),
|
).into(self.algo.unit.default),
|
||||||
chip_temp=web_system_info.get("temp"),
|
chip_temp=web_system_info.get("temp"),
|
||||||
temp=web_system_info.get("vrTemp"),
|
temp=web_system_info.get("vrTemp"),
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
from typing import List, Optional
|
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 Fan, HashBoard
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
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
|
||||||
@@ -124,8 +125,9 @@ class BMMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
|
rate=float(rpc_summary["SUMMARY"][0]["GHS 5s"]),
|
||||||
|
unit=self.algo.unit.GH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
@@ -183,8 +185,8 @@ class BMMiner(StockFirmware):
|
|||||||
|
|
||||||
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 = self.algo.hashrate(
|
||||||
hashrate, HashUnit.SHA256.GH
|
rate=float(hashrate), unit=self.algo.unit.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}")
|
||||||
@@ -245,8 +247,8 @@ class BMMiner(StockFirmware):
|
|||||||
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
|
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
rate_unit = "GH"
|
rate_unit = "GH"
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
rate=float(expected_rate), unit=self.algo.unit.from_str(rate_unit)
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ except ImportError:
|
|||||||
|
|
||||||
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 import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate, AlgoHashRateType
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.data import (
|
from pyasic.miners.data import (
|
||||||
DataFunction,
|
DataFunction,
|
||||||
@@ -222,7 +223,7 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
cfg = await self.get_config()
|
cfg = await self.get_config()
|
||||||
if cfg is None:
|
if cfg is None:
|
||||||
return False
|
return False
|
||||||
cfg.mining_mode = MiningModePowerTune(wattage)
|
cfg.mining_mode = MiningModePowerTune(power=wattage)
|
||||||
await self.send_config(cfg)
|
await self.send_config(cfg)
|
||||||
except APIError:
|
except APIError:
|
||||||
raise
|
raise
|
||||||
@@ -362,8 +363,9 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
|
rate=float(rpc_summary["SUMMARY"][0]["MHS 1m"]),
|
||||||
|
unit=self.algo.unit.MH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (KeyError, IndexError, ValueError, TypeError):
|
except (KeyError, IndexError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
@@ -434,8 +436,8 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
|
|
||||||
for board in rpc_devs["DEVS"]:
|
for board in rpc_devs["DEVS"]:
|
||||||
_id = board["ID"] - offset
|
_id = board["ID"] - offset
|
||||||
hashboards[_id].hashrate = AlgoHashRate.SHA256(
|
hashboards[_id].hashrate = self.algo.hashrate(
|
||||||
board["MHS 1m"], HashUnit.SHA256.MH
|
rate=float(board["MHS 1m"]), unit=self.algo.unit.MH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
pass
|
pass
|
||||||
@@ -481,7 +483,7 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
fans = []
|
fans = []
|
||||||
for n in range(self.expected_fans):
|
for n in range(self.expected_fans):
|
||||||
try:
|
try:
|
||||||
fans.append(Fan(rpc_fans["FANS"][n]["RPM"]))
|
fans.append(Fan(speed=rpc_fans["FANS"][n]["RPM"]))
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
pass
|
pass
|
||||||
return fans
|
return fans
|
||||||
@@ -512,7 +514,9 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
]:
|
]:
|
||||||
_error = board["Status"].split(" {")[0]
|
_error = board["Status"].split(" {")[0]
|
||||||
_error = _error[0].lower() + _error[1:]
|
_error = _error[0].lower() + _error[1:]
|
||||||
errors.append(BraiinsOSError(f"Slot {_id} {_error}"))
|
errors.append(
|
||||||
|
BraiinsOSError(error_message=f"Slot {_id} {_error}")
|
||||||
|
)
|
||||||
return errors
|
return errors
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
pass
|
pass
|
||||||
@@ -531,7 +535,7 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
|
|
||||||
async def _get_expected_hashrate(
|
async def _get_expected_hashrate(
|
||||||
self, rpc_devs: dict = None
|
self, rpc_devs: dict = None
|
||||||
) -> Optional[AlgoHashRate]:
|
) -> Optional[AlgoHashRateType]:
|
||||||
if rpc_devs is None:
|
if rpc_devs is None:
|
||||||
try:
|
try:
|
||||||
rpc_devs = await self.rpc.devs()
|
rpc_devs = await self.rpc.devs()
|
||||||
@@ -543,16 +547,21 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
hr_list = []
|
hr_list = []
|
||||||
|
|
||||||
for board in rpc_devs["DEVS"]:
|
for board in rpc_devs["DEVS"]:
|
||||||
expected_hashrate = round(float(board["Nominal MHS"] / 1000000), 2)
|
expected_hashrate = float(board["Nominal MHS"])
|
||||||
if expected_hashrate:
|
if expected_hashrate:
|
||||||
hr_list.append(expected_hashrate)
|
hr_list.append(expected_hashrate)
|
||||||
|
|
||||||
if len(hr_list) == 0:
|
if len(hr_list) == 0:
|
||||||
return AlgoHashRate.SHA256(0)
|
return self.algo.hashrate(
|
||||||
else:
|
rate=float(0), unit=self.algo.unit.default
|
||||||
return AlgoHashRate.SHA256(
|
|
||||||
(sum(hr_list) / len(hr_list)) * self.expected_hashboards
|
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
return self.algo.hashrate(
|
||||||
|
rate=float(
|
||||||
|
(sum(hr_list) / len(hr_list)) * self.expected_hashboards
|
||||||
|
),
|
||||||
|
unit=self.algo.unit.MH,
|
||||||
|
).into(self.algo.unit.default)
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -614,7 +623,7 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
pass
|
pass
|
||||||
return pools_data
|
return pools_data
|
||||||
|
|
||||||
async def upgrade_firmware(self, file: Path):
|
async def upgrade_firmware(self, file: Path) -> str:
|
||||||
"""
|
"""
|
||||||
Upgrade the firmware of the BOSMiner device.
|
Upgrade the firmware of the BOSMiner device.
|
||||||
|
|
||||||
@@ -622,7 +631,7 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
file (Path): The local file path of the firmware to be uploaded.
|
file (Path): The local file path of the firmware to be uploaded.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Confirmation message after upgrading the firmware.
|
Confirmation message after upgrading the firmware.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logging.info("Starting firmware upgrade process.")
|
logging.info("Starting firmware upgrade process.")
|
||||||
@@ -737,7 +746,7 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
"""Handler for new versions of BraiinsOS+ (post-gRPC)"""
|
"""Handler for new versions of BraiinsOS+ (post-gRPC)"""
|
||||||
|
|
||||||
_rpc_cls = BOSMinerRPCAPI
|
_rpc_cls = BOSMinerRPCAPI
|
||||||
web: BOSMinerRPCAPI
|
rpc: BOSMinerRPCAPI
|
||||||
_web_cls = BOSerWebAPI
|
_web_cls = BOSerWebAPI
|
||||||
web: BOSerWebAPI
|
web: BOSerWebAPI
|
||||||
|
|
||||||
@@ -889,8 +898,9 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
|
rate=float(rpc_summary["SUMMARY"][0]["MHS 1m"]),
|
||||||
|
unit=self.algo.unit.MH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (KeyError, IndexError, ValueError, TypeError):
|
except (KeyError, IndexError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
@@ -906,9 +916,11 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
|
|
||||||
if grpc_miner_details is not None:
|
if grpc_miner_details is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
grpc_miner_details["stickerHashrate"]["gigahashPerSecond"],
|
rate=float(
|
||||||
HashUnit.SHA256.GH,
|
grpc_miner_details["stickerHashrate"]["gigahashPerSecond"]
|
||||||
|
),
|
||||||
|
unit=self.algo.unit.GH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
@@ -933,18 +945,20 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
if board.get("chipsCount") is not None:
|
if board.get("chipsCount") is not None:
|
||||||
hashboards[idx].chips = board["chipsCount"]
|
hashboards[idx].chips = board["chipsCount"]
|
||||||
if board.get("boardTemp") is not None:
|
if board.get("boardTemp") is not None:
|
||||||
hashboards[idx].temp = board["boardTemp"]["degreeC"]
|
hashboards[idx].temp = int(board["boardTemp"]["degreeC"])
|
||||||
if board.get("highestChipTemp") is not None:
|
if board.get("highestChipTemp") is not None:
|
||||||
hashboards[idx].chip_temp = board["highestChipTemp"]["temperature"][
|
hashboards[idx].chip_temp = int(
|
||||||
"degreeC"
|
board["highestChipTemp"]["temperature"]["degreeC"]
|
||||||
]
|
)
|
||||||
if board.get("stats") is not None:
|
if board.get("stats") is not None:
|
||||||
if not board["stats"]["realHashrate"]["last5S"] == {}:
|
if not board["stats"]["realHashrate"]["last5S"] == {}:
|
||||||
hashboards[idx].hashrate = AlgoHashRate.SHA256(
|
hashboards[idx].hashrate = self.algo.hashrate(
|
||||||
board["stats"]["realHashrate"]["last5S"][
|
rate=float(
|
||||||
"gigahashPerSecond"
|
board["stats"]["realHashrate"]["last5S"][
|
||||||
],
|
"gigahashPerSecond"
|
||||||
HashUnit.SHA256.GH,
|
]
|
||||||
|
),
|
||||||
|
unit=self.algo.unit.GH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
hashboards[idx].missing = False
|
hashboards[idx].missing = False
|
||||||
|
|
||||||
@@ -993,7 +1007,7 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
fans = []
|
fans = []
|
||||||
for n in range(self.expected_fans):
|
for n in range(self.expected_fans):
|
||||||
try:
|
try:
|
||||||
fans.append(Fan(grpc_cooling_state["fans"][n]["rpm"]))
|
fans.append(Fan(speed=grpc_cooling_state["fans"][n]["rpm"]))
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
pass
|
pass
|
||||||
return fans
|
return fans
|
||||||
@@ -1024,7 +1038,9 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
]:
|
]:
|
||||||
_error = board["Status"].split(" {")[0]
|
_error = board["Status"].split(" {")[0]
|
||||||
_error = _error[0].lower() + _error[1:]
|
_error = _error[0].lower() + _error[1:]
|
||||||
errors.append(BraiinsOSError(f"Slot {_id} {_error}"))
|
errors.append(
|
||||||
|
BraiinsOSError(error_message=f"Slot {_id} {_error}")
|
||||||
|
)
|
||||||
return errors
|
return errors
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
@@ -1085,7 +1101,7 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
for group in grpc_pool_groups["poolGroups"]:
|
for group in grpc_pool_groups["poolGroups"]:
|
||||||
for idx, pool_info in enumerate(group["pools"]):
|
for idx, pool_info in enumerate(group["pools"]):
|
||||||
pool_data = PoolMetrics(
|
pool_data = PoolMetrics(
|
||||||
url=pool_info["url"],
|
url=PoolUrl.from_str(pool_info["url"]),
|
||||||
user=pool_info["user"],
|
user=pool_info["user"],
|
||||||
index=idx,
|
index=idx,
|
||||||
accepted=pool_info["stats"].get("acceptedShares", 0),
|
accepted=pool_info["stats"].get("acceptedShares", 0),
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ from typing import List, Optional
|
|||||||
import aiofiles
|
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 Fan, HashBoard
|
||||||
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.data.pools import PoolMetrics, PoolUrl
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
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
|
||||||
@@ -274,7 +275,7 @@ class BTMiner(StockFirmware):
|
|||||||
cfg.mining_mode = MiningModeConfig.normal()
|
cfg.mining_mode = MiningModeConfig.normal()
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
cfg.mining_mode = MiningModeConfig.power_tuning(power_lim)
|
cfg.mining_mode = MiningModeConfig.power_tuning(power=power_lim)
|
||||||
self.config = cfg
|
self.config = cfg
|
||||||
return self.config
|
return self.config
|
||||||
|
|
||||||
@@ -403,8 +404,9 @@ class BTMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
|
rate=float(rpc_summary["SUMMARY"][0]["MHS 1m"]),
|
||||||
|
unit=self.algo.unit.MH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
@@ -433,8 +435,8 @@ class BTMiner(StockFirmware):
|
|||||||
self.expected_hashboards += 1
|
self.expected_hashboards += 1
|
||||||
hashboards[board["ASC"]].chip_temp = round(board["Chip Temp Avg"])
|
hashboards[board["ASC"]].chip_temp = round(board["Chip Temp Avg"])
|
||||||
hashboards[board["ASC"]].temp = round(board["Temperature"])
|
hashboards[board["ASC"]].temp = round(board["Temperature"])
|
||||||
hashboards[board["ASC"]].hashrate = AlgoHashRate.SHA256(
|
hashboards[board["ASC"]].hashrate = self.algo.hashrate(
|
||||||
board["MHS 1m"], HashUnit.SHA256.MH
|
rate=float(board["MHS 1m"]), unit=self.algo.unit.MH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
hashboards[board["ASC"]].chips = board["Effective Chips"]
|
hashboards[board["ASC"]].chips = board["Effective Chips"]
|
||||||
hashboards[board["ASC"]].serial_number = board["PCB SN"]
|
hashboards[board["ASC"]].serial_number = board["PCB SN"]
|
||||||
@@ -498,8 +500,8 @@ class BTMiner(StockFirmware):
|
|||||||
try:
|
try:
|
||||||
if self.expected_fans > 0:
|
if self.expected_fans > 0:
|
||||||
fans = [
|
fans = [
|
||||||
Fan(rpc_summary["SUMMARY"][0].get("Fan Speed In", 0)),
|
Fan(speed=rpc_summary["SUMMARY"][0].get("Fan Speed In", 0)),
|
||||||
Fan(rpc_summary["SUMMARY"][0].get("Fan Speed Out", 0)),
|
Fan(speed=rpc_summary["SUMMARY"][0].get("Fan Speed Out", 0)),
|
||||||
]
|
]
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
@@ -583,8 +585,8 @@ class BTMiner(StockFirmware):
|
|||||||
try:
|
try:
|
||||||
expected_hashrate = rpc_summary["SUMMARY"][0]["Factory GHS"]
|
expected_hashrate = rpc_summary["SUMMARY"][0]["Factory GHS"]
|
||||||
if expected_hashrate:
|
if expected_hashrate:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
expected_hashrate, HashUnit.SHA256.GH
|
rate=float(expected_hashrate), unit=self.algo.unit.GH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
@@ -690,7 +692,7 @@ class BTMiner(StockFirmware):
|
|||||||
pass
|
pass
|
||||||
return pools_data
|
return pools_data
|
||||||
|
|
||||||
async def upgrade_firmware(self, file: Path):
|
async def upgrade_firmware(self, file: Path) -> str:
|
||||||
"""
|
"""
|
||||||
Upgrade the firmware of the Whatsminer device.
|
Upgrade the firmware of the Whatsminer device.
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, HashUnit
|
|
||||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
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
|
||||||
@@ -123,8 +123,9 @@ class CGMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return self.algo.hashrate(
|
||||||
rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
|
rate=float(rpc_summary["SUMMARY"][0]["GHS 5s"]),
|
||||||
|
unit=self.algo.unit.GH,
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ from pathlib import Path
|
|||||||
from typing import List, Optional
|
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 Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||||
from pyasic.data.pools import PoolMetrics
|
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||||
|
from pyasic.device.algorithm import AlgoHashRate
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||||
@@ -234,9 +235,9 @@ class ePIC(ePICFirmware):
|
|||||||
if web_summary["HBs"] is not None:
|
if web_summary["HBs"] is not None:
|
||||||
for hb in web_summary["HBs"]:
|
for hb in web_summary["HBs"]:
|
||||||
hashrate += hb["Hashrate"][0]
|
hashrate += hb["Hashrate"][0]
|
||||||
return AlgoHashRate.SHA256(hashrate, HashUnit.SHA256.MH).into(
|
return self.algo.hashrate(
|
||||||
HashUnit.SHA256.TH
|
rate=float(hashrate), unit=self.algo.unit.MH
|
||||||
)
|
).into(self.algo.unit.TH)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -260,9 +261,9 @@ class ePIC(ePICFirmware):
|
|||||||
ideal = hb["Hashrate"][1] / 100
|
ideal = hb["Hashrate"][1] / 100
|
||||||
|
|
||||||
hashrate += hb["Hashrate"][0] / ideal
|
hashrate += hb["Hashrate"][0] / ideal
|
||||||
return AlgoHashRate.SHA256(hashrate, HashUnit.SHA256.MH).into(
|
return self.algo.hashrate(
|
||||||
self.algo.unit.default
|
rate=float(hashrate), unit=self.algo.unit.MH
|
||||||
)
|
).into(self.algo.unit.default)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -293,7 +294,7 @@ class ePIC(ePICFirmware):
|
|||||||
if web_summary is not None:
|
if web_summary is not None:
|
||||||
for fan in web_summary["Fans Rpm"]:
|
for fan in web_summary["Fans Rpm"]:
|
||||||
try:
|
try:
|
||||||
fans.append(Fan(web_summary["Fans Rpm"][fan]))
|
fans.append(Fan(speed=web_summary["Fans Rpm"][fan]))
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
fans.append(Fan())
|
fans.append(Fan())
|
||||||
return fans
|
return fans
|
||||||
@@ -352,11 +353,11 @@ class ePIC(ePICFirmware):
|
|||||||
hashrate = hb["Hashrate"][0]
|
hashrate = hb["Hashrate"][0]
|
||||||
# Update the Hashboard object
|
# Update the Hashboard object
|
||||||
hb_list[hb["Index"]].missing = False
|
hb_list[hb["Index"]].missing = False
|
||||||
hb_list[hb["Index"]].hashrate = AlgoHashRate.SHA256(
|
hb_list[hb["Index"]].hashrate = self.algo.hashrate(
|
||||||
hashrate, HashUnit.SHA256.MH
|
rate=float(hashrate), unit=self.algo.unit.MH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
hb_list[hb["Index"]].chips = num_of_chips
|
hb_list[hb["Index"]].chips = num_of_chips
|
||||||
hb_list[hb["Index"]].temp = hb["Temperature"]
|
hb_list[hb["Index"]].temp = int(hb["Temperature"])
|
||||||
hb_list[hb["Index"]].tuned = tuned
|
hb_list[hb["Index"]].tuned = tuned
|
||||||
hb_list[hb["Index"]].active = active
|
hb_list[hb["Index"]].active = active
|
||||||
hb_list[hb["Index"]].voltage = hb["Input Voltage"]
|
hb_list[hb["Index"]].voltage = hb["Input Voltage"]
|
||||||
@@ -417,7 +418,7 @@ class ePIC(ePICFirmware):
|
|||||||
try:
|
try:
|
||||||
error = web_summary["Status"]["Last Error"]
|
error = web_summary["Status"]["Last Error"]
|
||||||
if error is not None:
|
if error is not None:
|
||||||
errors.append(X19Error(str(error)))
|
errors.append(X19Error(error_message=str(error)))
|
||||||
return errors
|
return errors
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@@ -437,6 +438,10 @@ class ePIC(ePICFirmware):
|
|||||||
web_summary.get("Session") is not None
|
web_summary.get("Session") is not None
|
||||||
and web_summary.get("Stratum") is not None
|
and web_summary.get("Stratum") is not None
|
||||||
):
|
):
|
||||||
|
url = web_summary["Stratum"].get("Current Pool")
|
||||||
|
# TODO: when scheme gets put in, update this
|
||||||
|
if url is not None:
|
||||||
|
url = PoolUrl.from_str(f"stratum+tcp://{url}")
|
||||||
pool_data.append(
|
pool_data.append(
|
||||||
PoolMetrics(
|
PoolMetrics(
|
||||||
accepted=web_summary["Session"].get("Accepted"),
|
accepted=web_summary["Session"].get("Accepted"),
|
||||||
@@ -445,7 +450,7 @@ class ePIC(ePICFirmware):
|
|||||||
remote_failures=0,
|
remote_failures=0,
|
||||||
active=web_summary["Stratum"].get("IsPoolConnected"),
|
active=web_summary["Stratum"].get("IsPoolConnected"),
|
||||||
alive=web_summary["Stratum"].get("IsPoolConnected"),
|
alive=web_summary["Stratum"].get("IsPoolConnected"),
|
||||||
url=web_summary["Stratum"].get("Current Pool"),
|
url=url,
|
||||||
user=web_summary["Stratum"].get("Current User"),
|
user=web_summary["Stratum"].get("Current User"),
|
||||||
index=web_summary["Stratum"].get("Config Id"),
|
index=web_summary["Stratum"].get("Config Id"),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from pyasic.config import MinerConfig, MiningModeConfig
|
from pyasic.config import MinerConfig, MiningModeConfig
|
||||||
from pyasic.data import AlgoHashRate, HashBoard, HashUnit
|
from pyasic.data import HashBoard
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.backends import BFGMiner
|
from pyasic.miners.backends import BFGMiner
|
||||||
@@ -162,8 +162,8 @@ class GoldshellMiner(BFGMiner):
|
|||||||
if board.get("ID") is not None:
|
if board.get("ID") is not None:
|
||||||
try:
|
try:
|
||||||
b_id = board["ID"]
|
b_id = board["ID"]
|
||||||
hashboards[b_id].hashrate = AlgoHashRate.SHA256(
|
hashboards[b_id].hashrate = self.algo.hashrate(
|
||||||
board["MHS 20s"], HashUnit.SHA256.MH
|
rate=float(board["MHS 20s"]), unit=self.algo.unit.MH
|
||||||
).into(self.algo.unit.default)
|
).into(self.algo.unit.default)
|
||||||
hashboards[b_id].temp = board["tstemp-2"]
|
hashboards[b_id].temp = board["tstemp-2"]
|
||||||
hashboards[b_id].missing = False
|
hashboards[b_id].missing = False
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user