Skip to content

API Guide

The Rust and Python APIs intentionally share names and behavior. This page summarizes the user-facing surface and points out the few language-specific differences.

Discovery

MinerFactory owns the scan range and discovery tuning. Connectivity retries are additional attempts after the initial probe. Setting retries to zero still performs one probe; later attempts use bounded exponential backoff and remain under the same scan concurrency limit. The default remains three retries; callers that want one pass can explicitly set zero.

Common miner ports are probed concurrently, returning after the first success. The scan concurrency limit also bounds the total number of active TCP probes, including probes made by connectivity retries.

The identification timeout is an end-to-end deadline covering discovery commands and firmware-specific miner construction. Discovery HTTP clients also apply explicit connection and total-request deadlines.

let factory = MinerFactory::from_subnet("192.168.1.0/24")?
    .with_concurrent_limit(2500)
    .with_connectivity_timeout_secs(1)
    .with_connectivity_retries(0)
    .with_identification_timeout_secs(10);
factory = (
    MinerFactory.from_subnet("192.168.1.0/24")
    .with_concurrent_limit(2500)
    .with_connectivity_timeout_secs(1)
    .with_connectivity_retries(0)
    .with_identification_timeout_secs(10)
)
Operation Rust Python
Known IP get_miner(ip).await? await get_miner(ip)
Full scan scan().await? await scan()
Stream found miners scan_stream() scan_stream()
Stream every IP scan_stream_with_ip() scan_stream_with_ip()

Miner Identity

Miner identity is available without awaiting because it is known when the miner handle is constructed.

Value Rust Python
IP address miner.get_ip() miner.ip
Make miner.get_device_info().make miner.make
Model miner.get_device_info().model miner.model
Firmware miner.get_device_info().firmware miner.firmware
Algorithm miner.get_device_info().algo miner.algo
Hardware shape miner.get_device_info().hardware miner.hardware

Data Collection

The full telemetry snapshot is MinerData. Individual getters return focused fields when a caller does not need the whole snapshot.

let data = miner.get_data().await;
let hashrate = miner.get_hashrate().await;
let fans = miner.get_fans().await;
data = await miner.get_data()
hashrate = await miner.get_hashrate()
fans = await miner.get_fans()

Common telemetry methods:

Field Method
MAC address get_mac
Serial number get_serial_number
Hostname get_hostname
Firmware version get_firmware_version
Hashboards get_hashboards
Hashrate get_hashrate
Fans get_fans
Wattage get_wattage
Messages get_messages
Pools get_pools
Mining state get_is_mining

Controls And Capability Checks

Not every miner supports every control. Rust exposes supports_*() methods; Python exposes matching supports_* properties.

Capability Control
supports_restart restart()
supports_pause pause()
supports_resume resume()
supports_set_fault_light set_fault_light(...)
supports_set_power_limit set_power_limit(...)
supports_change_password change_password(...)
supports_read_logs read_logs()
supports_factory_reset factory_reset()
supports_upgrade_firmware upgrade_firmware(...)

All miner handles also expose revalidate(), which re-runs that backend's firmware discovery checks against the same IP and returns whether the device is still valid for the existing miner handle.

if miner.supports_set_power_limit() {
    miner.set_power_limit(measurements::Power::from_watts(3200.0)).await?;
}
if miner.supports_set_power_limit:
    await miner.set_power_limit(3200.0)

Configuration Models

Configuration objects are shared concepts across Rust and Python. Python models are backed by Rust structs and expose Pydantic-style helpers.

use asic_rs::core::config::{
    fan::FanConfig,
    pools::{PoolConfig, PoolGroupConfig},
    tuning::TuningConfig,
};
use asic_rs::core::data::{miner::TuningTarget, pool::PoolURL};

let fan = FanConfig::manual(80);
let tuning = TuningConfig::new(TuningTarget::from_watts(3200.0));
let pool = PoolGroupConfig {
    name: "default".to_string(),
    quota: 1,
    pools: vec![PoolConfig {
        url: PoolURL::from("stratum+tcp://pool.example.com:3333".to_string()),
        username: "worker.1".to_string(),
        password: "x".to_string(),
    }],
};
from pyasic_rs.config import FanConfig, Pool, PoolGroup, TuningConfig

fan = FanConfig.manual(80)
tuning = TuningConfig.power(3200.0)
pool = PoolGroup(
    name="default",
    quota=1,
    pools=[
        Pool(
            url="stratum+tcp://pool.example.com:3333",
            username="worker.1",
            password="x",
        )
    ],
)

Use the matching config support property before reading or writing config:

Capability Get Set
supports_pools_config get_pools_config() set_pools_config(...)
supports_fan_config get_fan_config() set_fan_config(...)
supports_tuning_config get_tuning_config() set_tuning_config(...)
supports_scaling_config get_scaling_config() set_scaling_config(...)

Python Pydantic Interop

Python data/config classes can be used inside Pydantic models and support model_validate, model_dump, and model_json_schema where applicable.

from pydantic import BaseModel
from pyasic_rs.data import HashRate


class Snapshot(BaseModel):
    hashrate: HashRate


snapshot = Snapshot.model_validate(
    {"hashrate": {"value": 100.0, "unit": "TH/s", "algo": "SHA256"}}
)

print(snapshot.model_dump())