pyasic


Namepyasic JSON
Version 0.70.5 PyPI version JSON
download
home_pageNone
SummaryA simplified and standardized interface for Bitcoin ASICs.
upload_time2025-01-29 04:29:39
maintainerNone
docs_urlNone
authorUpstreamData
requires_python<4.0,>3.9
licenseApache 2.0
keywords python asic bitcoin whatsminer antminer braiins-os vnish luxos
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pyasic
*A simplified and standardized interface for Bitcoin ASICs.*

[![PyPI - Version](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/pyasic)](https://pypi.org/project/pyasic/)

[![Python - Supported Versions](https://img.shields.io/pypi/pyversions/pyasic.svg)](https://pypi.org/project/pyasic/)
[![CodeFactor - Grade](https://img.shields.io/codefactor/grade/github/UpstreamData/pyasic)](https://www.codefactor.io/repository/github/upstreamdata/pyasic)
[![Commit Activity - master](https://img.shields.io/github/commit-activity/y/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/commits/master/)

[![Code Style - Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Read The Docs - Docs](https://img.shields.io/readthedocs/pyasic)](https://docs.pyasic.org)
[![License - Apache 2.0](https://img.shields.io/github/license/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)

---
## Intro

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](https://docs.pyasic.org/en/latest/miners/supported_types/)

---
## 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`

##### Additional Developer Setup
```
poetry install --with dev
pre-commit install
```

##### Building Documentation Locally
```
poetry install --with docs
python docs/generate_miners.py
poetry run mkdocs serve
```

---
## 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.

##### Scanning for miners
To scan for miners in `pyasic`, we use the class `MinerNetwork`, which abstracts the search, communication, identification, setup, and return of a miner to 1 command.
The command `MinerNetwork.scan()` returns a list that contains any miners found.
```python
import asyncio  # asyncio for handling the async part
from pyasic.network import MinerNetwork  # miner network handles the scanning


async def scan_miners():  # define async scan function to allow awaiting
    # create a miner network
    # 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
    # this will return the correct type of miners if they are supported with all functionality.
    miners = await network.scan()
    print(miners)

if __name__ == "__main__":
    asyncio.run(scan_miners())  # run the scan asynchronously with asyncio.run()
```

---
##### Creating miners based on IP
If you already know the IP address of your miner or miners, you can use the `MinerFactory` to communicate and identify the miners, or an abstraction of its functionality, `get_miner()`.
The function `get_miner()` will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.
```python
import asyncio  # asyncio for handling the async part
from pyasic import get_miner # handles miner creation


async def get_miners():  # define async scan function to allow awaiting
    # get the miner with the miner factory
    # 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")
    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")]
    miners = await asyncio.gather(*tasks)
    print(miners)


if __name__ == "__main__":
    asyncio.run(get_miners())  # get the miners asynchronously with asyncio.run()
```

---
## 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()`.
This function will return an instance of the dataclass `MinerData` with all data it can gather from the miner.
Each piece of data in a `MinerData` instance can be referenced by getting it as an attribute, such as `MinerData().hashrate`.

##### One miner
```python
import asyncio
from pyasic import get_miner

async def gather_miner_data():
    miner = await get_miner("192.168.1.75")
    if miner is not None:
        miner_data = await miner.get_data()
        print(miner_data)  # all data from the dataclass
        print(miner_data.hashrate)  # hashrate of the miner in TH/s

if __name__ == "__main__":
    asyncio.run(gather_miner_data())
```
---
##### 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.
```python
import asyncio  # asyncio for handling the async part
from pyasic.network import MinerNetwork  # miner network handles the scanning


async def gather_miner_data():  # define async scan function to allow awaiting
    network = MinerNetwork.from_subnet("192.168.1.50/24")
    miners = await network.scan()

    # 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])

    for miner_data in all_miner_data:
        print(miner_data)    # print out all the data one by one

if __name__ == "__main__":
    asyncio.run(gather_miner_data())
```

---
## Miner control

`pyasic` exposes a standard interface for each miner using control functions.
Every miner class in `pyasic` must implement all the control functions defined in `BaseMiner`.

These functions are
`check_light`,
`fault_light_off`,
`fault_light_on`,
`get_config`,
`get_data`,
`get_errors`,
`get_hostname`,
`get_model`,
`reboot`,
`restart_backend`,
`stop_mining`,
`resume_mining`,
`is_mining`,
`send_config`, and
`set_power_limit`.

##### Usage
```python
import asyncio
from pyasic import get_miner


async def set_fault_light():
    miner = await get_miner("192.168.1.20")

    # call control function
    await miner.fault_light_on()

if __name__ == "__main__":
    asyncio.run(set_fault_light())
```

---
## Helper dataclasses

##### `MinerConfig` and `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()`.

---

##### MinerData

`MinerData` is a return from the [`get_data()`](#get-data) function, and is used to have a consistent dataset across all returns.

You can call `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.

`MinerData` instances can also be added to each other to combine their data and can be divided by a number to divide all their data, allowing you to get average data from many miners by doing -
```python
from pyasic import MinerData

# examples of miner data
d1 = MinerData("192.168.1.1")
d2 = MinerData("192.168.1.2")

list_of_miner_data = [d1, d2]

average_data = sum(list_of_miner_data, start=MinerData("0.0.0.0"))/len(list_of_miner_data)
```

---

##### MinerConfig

`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).

Each miner has a unique way to convert the `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` and will do the conversion to the right type for you.

You can use the `MinerConfig` as follows:
```python
import asyncio
from pyasic import get_miner


async def set_fault_light():
    miner = await get_miner("192.168.1.20")

    # get config
    cfg = await miner.get_config()

    # send config
    await miner.send_config(cfg)

if __name__ == "__main__":
    asyncio.run(set_fault_light())

```

---
## 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:

```python
from pyasic import settings

settings.update("default_antminer_web_password", "my_pwd")
```

##### Default values:
```
"network_ping_retries": 1,
"network_ping_timeout": 3,
"network_scan_semaphore": None,
"factory_get_retries": 1,
"factory_get_timeout": 3,
"get_data_retries": 1,
"api_function_timeout": 5,
"antminer_mining_mode_as_str": False,
"default_whatsminer_rpc_password": "admin",
"default_innosilicon_web_password": "admin",
"default_antminer_web_password": "root",
"default_bosminer_web_password": "root",
"default_vnish_web_password": "admin",
"default_goldshell_web_password": "123456789",
"default_auradine_web_password": "admin",
"default_epic_web_password": "letmein",
"default_hive_web_password": "admin",
"default_antminer_ssh_password": "miner",
"default_bosminer_ssh_password": "root",

# ADVANCED
# Only use this if you know what you are doing
"socket_linger_time": 1000,
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pyasic",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>3.9",
    "maintainer_email": null,
    "keywords": "python, asic, bitcoin, whatsminer, antminer, braiins-os, vnish, luxos",
    "author": "UpstreamData",
    "author_email": "brett@upstreamdata.ca",
    "download_url": "https://files.pythonhosted.org/packages/b8/58/1a1af4c06491417ac201edf3efb1e6ad3072c52826bb22b6ea59fde4beb2/pyasic-0.70.5.tar.gz",
    "platform": null,
    "description": "# pyasic\n*A simplified and standardized interface for Bitcoin ASICs.*\n\n[![PyPI - Version](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/pyasic)](https://pypi.org/project/pyasic/)\n\n[![Python - Supported Versions](https://img.shields.io/pypi/pyversions/pyasic.svg)](https://pypi.org/project/pyasic/)\n[![CodeFactor - Grade](https://img.shields.io/codefactor/grade/github/UpstreamData/pyasic)](https://www.codefactor.io/repository/github/upstreamdata/pyasic)\n[![Commit Activity - master](https://img.shields.io/github/commit-activity/y/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/commits/master/)\n\n[![Code Style - Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Read The Docs - Docs](https://img.shields.io/readthedocs/pyasic)](https://docs.pyasic.org)\n[![License - Apache 2.0](https://img.shields.io/github/license/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)\n\n---\n## Intro\n\nWelcome to `pyasic`!  `pyasic` uses an asynchronous method of communicating with ASIC miners on your network, which makes it super fast.\n\n[Click here to view supported miner types](https://docs.pyasic.org/en/latest/miners/supported_types/)\n\n---\n## Installation\n\nIt 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:\n  - [pypoetry](https://python-poetry.org/): the reccommended way, since pyasic already uses it by default\n\n```\n    poetry install\n```\n\n  - [venv](https://docs.python.org/3/library/venv.html): included in Python standard library but has fewer features than other options\n  - [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv): [pyenv](https://github.com/pyenv/pyenv) plugin for managing virtualenvs\n\n```\n    pyenv install <python version number>\n    pyenv virtualenv <python version number> <env name>\n    pyenv activate <env name>\n```\n\n  - [conda](https://docs.conda.io/en/latest/)\n\n##### Installing `pyasic`\n\n`python -m pip install pyasic` or `poetry install`\n\n##### Additional Developer Setup\n```\npoetry install --with dev\npre-commit install\n```\n\n##### Building Documentation Locally\n```\npoetry install --with docs\npython docs/generate_miners.py\npoetry run mkdocs serve\n```\n\n---\n## Getting started\n\nGetting 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.\n\n##### Scanning for miners\nTo scan for miners in `pyasic`, we use the class `MinerNetwork`, which abstracts the search, communication, identification, setup, and return of a miner to 1 command.\nThe command `MinerNetwork.scan()` returns a list that contains any miners found.\n```python\nimport asyncio  # asyncio for handling the async part\nfrom pyasic.network import MinerNetwork  # miner network handles the scanning\n\n\nasync def scan_miners():  # define async scan function to allow awaiting\n    # create a miner network\n    # you can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs).\n    network = MinerNetwork.from_subnet(\"192.168.1.50/24\")  # this uses the 192.168.1.0-255 network\n\n    # scan for miners asynchronously\n    # this will return the correct type of miners if they are supported with all functionality.\n    miners = await network.scan()\n    print(miners)\n\nif __name__ == \"__main__\":\n    asyncio.run(scan_miners())  # run the scan asynchronously with asyncio.run()\n```\n\n---\n##### Creating miners based on IP\nIf you already know the IP address of your miner or miners, you can use the `MinerFactory` to communicate and identify the miners, or an abstraction of its functionality, `get_miner()`.\nThe function `get_miner()` will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.\n```python\nimport asyncio  # asyncio for handling the async part\nfrom pyasic import get_miner # handles miner creation\n\n\nasync def get_miners():  # define async scan function to allow awaiting\n    # get the miner with the miner factory\n    # the miner factory is a singleton, and will always use the same object and cache\n    # this means you can always call it as MinerFactory().get_miner(), or just get_miner()\n    miner_1 = await get_miner(\"192.168.1.75\")\n    miner_2 = await get_miner(\"192.168.1.76\")\n    print(miner_1, miner_2)\n\n    # can also gather these, since they are async\n    # gathering them will get them both at the same time\n    # this makes it much faster to get a lot of miners at a time\n    tasks = [get_miner(\"192.168.1.75\"), get_miner(\"192.168.1.76\")]\n    miners = await asyncio.gather(*tasks)\n    print(miners)\n\n\nif __name__ == \"__main__\":\n    asyncio.run(get_miners())  # get the miners asynchronously with asyncio.run()\n```\n\n---\n## Data gathering\n\nOnce 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()`.\nThis function will return an instance of the dataclass `MinerData` with all data it can gather from the miner.\nEach piece of data in a `MinerData` instance can be referenced by getting it as an attribute, such as `MinerData().hashrate`.\n\n##### One miner\n```python\nimport asyncio\nfrom pyasic import get_miner\n\nasync def gather_miner_data():\n    miner = await get_miner(\"192.168.1.75\")\n    if miner is not None:\n        miner_data = await miner.get_data()\n        print(miner_data)  # all data from the dataclass\n        print(miner_data.hashrate)  # hashrate of the miner in TH/s\n\nif __name__ == \"__main__\":\n    asyncio.run(gather_miner_data())\n```\n---\n##### Multiple miners\nYou can do something similar with multiple miners, with only needing to make a small change to get all the data at once.\n```python\nimport asyncio  # asyncio for handling the async part\nfrom pyasic.network import MinerNetwork  # miner network handles the scanning\n\n\nasync def gather_miner_data():  # define async scan function to allow awaiting\n    network = MinerNetwork.from_subnet(\"192.168.1.50/24\")\n    miners = await network.scan()\n\n    # we need to asyncio.gather() all the miners get_data() functions to make them run together\n    all_miner_data = await asyncio.gather(*[miner.get_data() for miner in miners])\n\n    for miner_data in all_miner_data:\n        print(miner_data)    # print out all the data one by one\n\nif __name__ == \"__main__\":\n    asyncio.run(gather_miner_data())\n```\n\n---\n## Miner control\n\n`pyasic` exposes a standard interface for each miner using control functions.\nEvery miner class in `pyasic` must implement all the control functions defined in `BaseMiner`.\n\nThese functions are\n`check_light`,\n`fault_light_off`,\n`fault_light_on`,\n`get_config`,\n`get_data`,\n`get_errors`,\n`get_hostname`,\n`get_model`,\n`reboot`,\n`restart_backend`,\n`stop_mining`,\n`resume_mining`,\n`is_mining`,\n`send_config`, and\n`set_power_limit`.\n\n##### Usage\n```python\nimport asyncio\nfrom pyasic import get_miner\n\n\nasync def set_fault_light():\n    miner = await get_miner(\"192.168.1.20\")\n\n    # call control function\n    await miner.fault_light_on()\n\nif __name__ == \"__main__\":\n    asyncio.run(set_fault_light())\n```\n\n---\n## Helper dataclasses\n\n##### `MinerConfig` and `MinerData`\n\n`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()`.\n\n---\n\n##### MinerData\n\n`MinerData` is a return from the [`get_data()`](#get-data) function, and is used to have a consistent dataset across all returns.\n\nYou can call `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.\n\n`MinerData` instances can also be added to each other to combine their data and can be divided by a number to divide all their data, allowing you to get average data from many miners by doing -\n```python\nfrom pyasic import MinerData\n\n# examples of miner data\nd1 = MinerData(\"192.168.1.1\")\nd2 = MinerData(\"192.168.1.2\")\n\nlist_of_miner_data = [d1, d2]\n\naverage_data = sum(list_of_miner_data, start=MinerData(\"0.0.0.0\"))/len(list_of_miner_data)\n```\n\n---\n\n##### MinerConfig\n\n`MinerConfig` is `pyasic`'s way to represent a configuration file from a miner.\nIt is designed to unionize the configuration of all supported miner types, and is the return from [`get_config()`](#get-config).\n\nEach miner has a unique way to convert the `MinerConfig` to their specific type, there are helper functions in the class.\nIn most cases these helper functions should not be used, as [`send_config()`](#send-config) takes a [`MinerConfig` and will do the conversion to the right type for you.\n\nYou can use the `MinerConfig` as follows:\n```python\nimport asyncio\nfrom pyasic import get_miner\n\n\nasync def set_fault_light():\n    miner = await get_miner(\"192.168.1.20\")\n\n    # get config\n    cfg = await miner.get_config()\n\n    # send config\n    await miner.send_config(cfg)\n\nif __name__ == \"__main__\":\n    asyncio.run(set_fault_light())\n\n```\n\n---\n## Settings\n\n`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:\n\n```python\nfrom pyasic import settings\n\nsettings.update(\"default_antminer_web_password\", \"my_pwd\")\n```\n\n##### Default values:\n```\n\"network_ping_retries\": 1,\n\"network_ping_timeout\": 3,\n\"network_scan_semaphore\": None,\n\"factory_get_retries\": 1,\n\"factory_get_timeout\": 3,\n\"get_data_retries\": 1,\n\"api_function_timeout\": 5,\n\"antminer_mining_mode_as_str\": False,\n\"default_whatsminer_rpc_password\": \"admin\",\n\"default_innosilicon_web_password\": \"admin\",\n\"default_antminer_web_password\": \"root\",\n\"default_bosminer_web_password\": \"root\",\n\"default_vnish_web_password\": \"admin\",\n\"default_goldshell_web_password\": \"123456789\",\n\"default_auradine_web_password\": \"admin\",\n\"default_epic_web_password\": \"letmein\",\n\"default_hive_web_password\": \"admin\",\n\"default_antminer_ssh_password\": \"miner\",\n\"default_bosminer_ssh_password\": \"root\",\n\n# ADVANCED\n# Only use this if you know what you are doing\n\"socket_linger_time\": 1000,\n```\n",
    "bugtrack_url": null,
    "license": "Apache 2.0",
    "summary": "A simplified and standardized interface for Bitcoin ASICs.",
    "version": "0.70.5",
    "project_urls": null,
    "split_keywords": [
        "python",
        " asic",
        " bitcoin",
        " whatsminer",
        " antminer",
        " braiins-os",
        " vnish",
        " luxos"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f1afd6e5b6839143fd7d7713b4d22e16270732f0ae95d1a2efc367ec79483768",
                "md5": "804b58c282cf6c1fe2396ccb0019ceda",
                "sha256": "7065d4baa246ae98bd227b2b8977a02d50249023b982de73f1ce561f4f793983"
            },
            "downloads": -1,
            "filename": "pyasic-0.70.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "804b58c282cf6c1fe2396ccb0019ceda",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>3.9",
            "size": 453294,
            "upload_time": "2025-01-29T04:29:37",
            "upload_time_iso_8601": "2025-01-29T04:29:37.482215Z",
            "url": "https://files.pythonhosted.org/packages/f1/af/d6e5b6839143fd7d7713b4d22e16270732f0ae95d1a2efc367ec79483768/pyasic-0.70.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b8581a1af4c06491417ac201edf3efb1e6ad3072c52826bb22b6ea59fde4beb2",
                "md5": "d328d73090ab7285e1b3297d234ad4dd",
                "sha256": "49ee928285d7e7929ff816e137f6d46008636cecce2f2919210fcc2a178cfc6a"
            },
            "downloads": -1,
            "filename": "pyasic-0.70.5.tar.gz",
            "has_sig": false,
            "md5_digest": "d328d73090ab7285e1b3297d234ad4dd",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>3.9",
            "size": 167873,
            "upload_time": "2025-01-29T04:29:39",
            "upload_time_iso_8601": "2025-01-29T04:29:39.933144Z",
            "url": "https://files.pythonhosted.org/packages/b8/58/1a1af4c06491417ac201edf3efb1e6ad3072c52826bb22b6ea59fde4beb2/pyasic-0.70.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-01-29 04:29:39",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "pyasic"
}
        
Elapsed time: 0.75330s