Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions asic-rs-core/src/data/firmware.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
use std::path::Path;

use anyhow::Context;
#[cfg(feature = "python")]
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use tokio::io::AsyncReadExt;

/// Result of checking a miner for an available firmware update.
///
/// Read-only and obtained on demand (a firmware-update check usually hits the
/// vendor's release server, so it is not part of the regular telemetry poll).
#[cfg_attr(
feature = "python",
pyclass(get_all, skip_from_py_object, module = "asic_rs")
)]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct FirmwareUpdate {
/// The firmware version currently installed, if known.
pub current_version: Option<String>,
/// The latest firmware version offered by the vendor, if any.
pub latest_version: Option<String>,
/// Whether a newer firmware than the installed one is available.
pub update_available: bool,
/// Release date of the latest firmware, as reported by the vendor.
pub release_date: Option<String>,
/// URL of the latest firmware release, when provided.
pub release_url: Option<String>,
}
Comment thread
b-rowan marked this conversation as resolved.

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FirmwareImage {
pub filename: String,
Expand Down
15 changes: 14 additions & 1 deletion asic-rs-core/src/traits/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
command::MinerCommand,
device::DeviceInfo,
fan::FanData,
firmware::FirmwareImage,
firmware::{FirmwareImage, FirmwareUpdate},
hashrate::{HashRate, HashRateUnit},
message::MinerMessage,
miner::{MinerData, TuningTarget},
Expand Down Expand Up @@ -808,6 +808,19 @@ pub trait UpgradeFirmware {
fn supports_upgrade_firmware(&self) -> bool {
false
}

/// Check whether a newer firmware is available for this miner.
///
/// This is an on-demand call (it typically queries the vendor's release
/// server), not part of the regular telemetry poll. Defaults to
/// unsupported.
async fn check_firmware_update(&self) -> anyhow::Result<FirmwareUpdate> {
anyhow::bail!("Checking for firmware updates is not supported on this platform");
}

fn supports_check_firmware_update(&self) -> bool {
false
}
}

// Config traits
Expand Down
46 changes: 46 additions & 0 deletions asic-rs-firmwares/braiins/src/backends/v26_04/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use asic_rs_core::{
command::MinerCommand,
device::{DeviceInfo, HashAlgorithm},
fan::FanData,
firmware::FirmwareUpdate,
hashrate::{HashRate, HashRateUnit},
message::{MessageSeverity, MinerMessage},
miner::TuningTarget,
Expand Down Expand Up @@ -831,6 +832,51 @@ impl UpgradeFirmware for BraiinsV2604 {
fn supports_upgrade_firmware(&self) -> bool {
false
}

fn supports_check_firmware_update(&self) -> bool {
true
}

/// Reads the installed version and asks BOS to check the vendor's release
/// server (`bos.checkForUpgrade`) via the authenticated GraphQL client.
async fn check_firmware_update(&self) -> anyhow::Result<FirmwareUpdate> {
const GQL_CHECK_UPGRADE: MinerCommand = MinerCommand::GraphQL {
command: r#"{
bos {
info { version { full } }
checkForUpgrade {
__typename
... on UpgradeDetail {
latestRelease {
version
releaseDate
url
}
}
}
}
}"#,
};
let data = self.graphql.get_api_result(&GQL_CHECK_UPGRADE).await?;

let s = |p: &str| -> Option<String> {
data.pointer(p).and_then(|v| v.as_str()).map(String::from)
};
let current_version = s("/bos/info/version/full");
let latest_version = s("/bos/checkForUpgrade/latestRelease/version");
let release_date = s("/bos/checkForUpgrade/latestRelease/releaseDate");
let release_url = s("/bos/checkForUpgrade/latestRelease/url");
let update_available =
latest_version.is_some() && latest_version.as_deref() != current_version.as_deref();

Ok(FirmwareUpdate {
current_version,
latest_version,
update_available,
release_date,
release_url,
})
}
}
Comment on lines +835 to 878

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be able to backport to all the other braiins versions.


impl HasDefaultAuth for BraiinsV2604 {
Expand Down
15 changes: 15 additions & 0 deletions python/pyasic_rs/asic_rs.pyi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 18 additions & 1 deletion src/python/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use asic_rs_core::{
board::BoardData,
device::{HashAlgorithm, MinerHardware},
fan::FanData,
firmware::FirmwareImage,
firmware::{FirmwareImage, FirmwareUpdate},
hashrate::HashRate,
message::MinerMessage,
miner::{MinerData, TuningTarget},
Expand Down Expand Up @@ -210,6 +210,11 @@ impl Miner {
fn supports_upgrade_firmware(&self, py: Python<'_>) -> bool {
self.with_miner(py, |miner| miner.supports_upgrade_firmware())
}
/// Whether this miner supports checking for an available firmware update.
#[getter]
fn supports_check_firmware_update(&self, py: Python<'_>) -> bool {
self.with_miner(py, |miner| miner.supports_check_firmware_update())
}
/// Whether this miner supports scaling configuration.
#[getter]
fn supports_scaling_config(&self, py: Python<'_>) -> bool {
Expand Down Expand Up @@ -257,6 +262,18 @@ impl Miner {
}
})
}
/// Check for an available firmware update (on-demand; queries the vendor's
/// release server). Returns `None` if unsupported or the check fails.
pub fn check_firmware_update<'a>(
&self,
py: Python<'a>,
) -> PyResult<PyAwaitable<Option<FirmwareUpdate>>> {
let inner = Arc::clone(&self.inner);
future_into_py(py, async move {
let inner = inner.read().await;
Ok(inner.check_firmware_update().await.ok())
})
}
/// Await the miner MAC address, if exposed by the firmware.
pub fn get_mac<'a>(&self, py: Python<'a>) -> PyResult<PyAwaitable<Option<String>>> {
let inner = Arc::clone(&self.inner);
Expand Down
1 change: 1 addition & 0 deletions src/python/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod asic_rs {
board::{BoardData, ChipData, MinerControlBoard},
device::{DeviceInfo, MinerHardware},
fan::FanData,
firmware::FirmwareUpdate,
message::{MessageSeverity, MinerComponent, MinerMessage},
miner::{MinerData, PyTuningTarget as TuningTarget},
pool::{PoolData, PoolGroupData, PoolScheme, PoolURL},
Expand Down