pyasic
A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH.
Intro
Welcome to pyasic! Pyasic uses an asynchronous method of communicating with asic miners on your network, which makes it super fast.
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_network_for_miners()
returns a list that contains any miners found.
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("192.168.1.50") # 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_network_for_miners()
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.
The function MinerFactory().get_miner()
will return any miner it found at the IP address specified, or an UnknownMiner
if it cannot identify the miner.
import asyncio # asyncio for handling the async part
from pyasic.miners.miner_factory import MinerFactory # miner factory handles miners creation
async def get_miners(): # define async scan function to allow awaiting
# get the miner with miner factory
# 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()
miner_1 = await MinerFactory().get_miner("192.168.1.75")
miner_2 = await MinerFactory().get_miner("192.168.1.76")
print(miner_1, miner_2)
if __name__ == "__main__":
asyncio.run(get_miners()) # get the miners asynchronously with asyncio.run()
Getting data from miners
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 a 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
.
import asyncio
from pyasic.miners.miner_factory import MinerFactory
async def gather_miner_data():
miner = await MinerFactory().get_miner("192.168.1.75")
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())
You can do something similar with multiple miners, with only needing to make a small change to get all the data at once.
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("192.168.1.50")
miners = await network.scan_network_for_miners()
# 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())
Controlling miners via pyasic
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
,
send_config
, and
set_power_limit
.
Check Light
Source code in pyasic/miners/base.py
96 97 |
|
Fault Light Off
Turn the fault light of the miner off and return success as a boolean.
Returns:
Type | Description |
---|---|
bool
|
A boolean value of the success of turning the light off. |
Source code in pyasic/miners/base.py
108 109 110 111 112 113 114 115 |
|
Fault Light On
Turn the fault light of the miner on and return success as a boolean.
Returns:
Type | Description |
---|---|
bool
|
A boolean value of the success of turning the light on. |
Source code in pyasic/miners/base.py
99 100 101 102 103 104 105 106 |
|
Get Config
Get the mining configuration of the miner and return it as a MinerConfig
.
Returns:
Type | Description |
---|---|
MinerConfig
|
A |
Source code in pyasic/miners/base.py
117 118 119 120 121 122 123 124 125 |
|
Get Data
Get data from the miner in the form of MinerData
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
allow_warning |
bool
|
Allow warning when an API command fails. |
False
|
data_to_get |
list
|
Names of data items you want to gather. Defaults to all data. |
None
|
Returns:
Type | Description |
---|---|
MinerData
|
A |
Source code in pyasic/miners/base.py
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
|
Get Errors
Get a list of the errors the miner is experiencing.
Returns:
Type | Description |
---|---|
List[MinerErrorData]
|
A list of error classes representing different errors. |
Source code in pyasic/miners/base.py
315 316 317 318 319 320 321 322 |
|
Get Hostname
Get the hostname of the miner and return it as a string.
Returns:
Type | Description |
---|---|
Optional[str]
|
A string representing the hostname of the miner. |
Source code in pyasic/miners/base.py
234 235 236 237 238 239 240 241 |
|
Get Model
Get the model of the miner and return it as a string.
Returns:
Type | Description |
---|---|
Optional[str]
|
A string representing the model of the miner. |
Source code in pyasic/miners/base.py
198 199 200 201 202 203 204 205 |
|
Reboot
Reboot the miner and return success as a boolean.
Returns:
Type | Description |
---|---|
bool
|
A boolean value of the success of rebooting the miner. |
Source code in pyasic/miners/base.py
127 128 129 130 131 132 133 134 |
|
Restart Backend
Restart the mining process of the miner (bosminer, bmminer, cgminer, etc) and return success as a boolean.
Returns:
Type | Description |
---|---|
bool
|
A boolean value of the success of restarting the mining process. |
Source code in pyasic/miners/base.py
136 137 138 139 140 141 142 143 |
|
Stop Mining
Stop the mining process of the miner.
Returns:
Type | Description |
---|---|
bool
|
A boolean value of the success of stopping the mining process. |
Source code in pyasic/miners/base.py
155 156 157 158 159 160 161 162 |
|
Resume Mining
Resume the mining process of the miner.
Returns:
Type | Description |
---|---|
bool
|
A boolean value of the success of resuming the mining process. |
Source code in pyasic/miners/base.py
164 165 166 167 168 169 170 171 |
|
Send Config
Set the mining configuration of the miner.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
config |
MinerConfig
|
A |
required |
user_suffix |
str
|
A suffix to append to the username when sending to the miner. |
None
|
Source code in pyasic/miners/base.py
145 146 147 148 149 150 151 152 153 |
|
Set Power Limit
Set the power limit to be used by the miner.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
wattage |
int
|
The power limit to set on the miner. |
required |
Returns:
Type | Description |
---|---|
bool
|
A boolean value of the success of setting the power limit. |
Source code in pyasic/miners/base.py
173 174 175 176 177 178 179 180 181 182 183 |
|
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()
function, and is used to have a consistent dataset across all returns.
You can call MinerData.asdict()
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 -
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 the return from 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()
takes a MinerConfig
and will do the conversion to the right type for you.