Skip to content

Getting Started

All network operations are asynchronous. Rust uses async methods returning Result<T> where an operation can fail. Python exposes awaitable methods and uses None for values or operations that are unavailable for a miner.

Get One Miner

If you know a miner's IP address, let the factory identify the firmware and construct the matching miner implementation.

use asic_rs::MinerFactory;
use std::{net::IpAddr, str::FromStr};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let factory = MinerFactory::new();
    let ip = IpAddr::from_str("192.168.1.10")?;

    if let Some(miner) = factory.get_miner(ip).await? {
        println!(
            "Found {} {} at {}",
            miner.get_device_info().make,
            miner.get_device_info().model,
            ip
        );
    }

    Ok(())
}
import asyncio

from pyasic_rs import MinerFactory


async def main() -> None:
    factory = MinerFactory()
    miner = await factory.get_miner("192.168.1.10")

    if miner is not None:
        print(f"Found {miner.make} {miner.model} at {miner.ip}")


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

Scan A Network

Use a subnet, octet selectors, or range string when the exact IP address is not known. Large scans use bounded concurrency.

use asic_rs::MinerFactory;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let miners = MinerFactory::from_subnet("192.168.1.0/24")?
        .with_concurrent_limit(2500)
        .scan()
        .await?;

    println!("Found {} miner(s)", miners.len());
    Ok(())
}
import asyncio

from pyasic_rs import MinerFactory


async def main() -> None:
    miners = await (
        MinerFactory.from_subnet("192.168.1.0/24")
        .with_concurrent_limit(2500)
        .scan()
    )

    print(f"Found {len(miners)} miner(s)")


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

Range helpers are available in both languages.

let by_octets = MinerFactory::from_octets("192", "168", "1", "1-255")?;
let by_range = MinerFactory::from_range("192.168.1.1-255")?;
by_octets = MinerFactory.from_octets("192", "168", "1", "1-255")
by_range = MinerFactory.from_range("192.168.1.1-255")

Stream Results

Streaming scans let you act on miners as soon as they are found.

use asic_rs::MinerFactory;
use futures::StreamExt;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut stream = MinerFactory::from_subnet("192.168.1.0/24")?.scan_stream();

    while let Some(miner) = stream.next().await {
        println!("{} {}", miner.get_device_info().make, miner.get_device_info().model);
    }

    Ok(())
}
factory = MinerFactory.from_subnet("192.168.1.0/24")

async for miner in factory.scan_stream():
    print(f"{miner.make} {miner.model}")

Use the IP-preserving stream when you need to track unsupported or offline addresses.

let mut stream = MinerFactory::from_subnet("192.168.1.0/24")?.scan_stream_with_ip();

while let Some((ip, miner)) = stream.next().await {
    println!("{ip}: {}", miner.is_some());
}
async for ip, miner in factory.scan_stream_with_ip():
    print(ip, miner is not None)

Gather Data

get_data() returns a full standardized telemetry snapshot. Focused get_* methods are useful when you only need one field.

let data = miner.get_data().await;
let mac = miner.get_mac().await;

println!("{} is mining: {}", data.ip, data.is_mining);
println!("MAC: {mac:?}");
data = await miner.get_data()
mac = await miner.get_mac()

print(f"{data.ip} is mining: {data.is_mining}")
print(f"MAC: {mac}")

Skip expensive fields when you do not need them.

use asic_rs::core::data::collector::DataField;

let data = miner
    .get_data_filtered(vec![DataField::Hashboards, DataField::Chips])
    .await;
from pyasic_rs.data import DataField

data = await miner.get_data(exclude=[DataField.Hashboards, DataField.Chips])

Authenticate

Backends use their built-in default credentials unless you override them. Set credentials before starting concurrent operations on that miner handle.

use asic_rs::core::traits::auth::MinerAuth;

miner.set_auth(MinerAuth::new("admin", "secret"));
let data = miner.get_data().await;
miner.set_auth("admin", "secret")
data = await miner.get_data()

Control A Miner

Control support depends on miner make, model, and firmware. Check the matching support value before exposing controls in user-facing tools.

if miner.supports_restart() {
    let restarted = miner.restart().await?;
    println!("Restart accepted: {restarted}");
}
if miner.supports_restart:
    restarted = await miner.restart()
    print(f"Restart accepted: {restarted}")