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())