feat(firmware): on-demand firmware-update check#294
Conversation
Adds an on-demand "is newer firmware available?" check, separate from the telemetry poll (it hits the vendor's release server). - New FirmwareUpdate result type (current/latest version, update_available, release date/url) returned by UpgradeFirmware::check_firmware_update, default unsupported. - BraiinsOS 26.04 reads bos.checkForUpgrade + bos.info.version via the authenticated GraphQL client. - Python: Miner.check_firmware_update() + supports_check_firmware_update.
|
|
||
| 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, | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Should be able to backport to all the other braiins versions.
|
Thanks for the review — but before reworking I'd push back on this direction, because a couple of parts don't hold up across the firmwares: semver won't work as the comparison basis. Miner firmware versions aren't semver: BraiinsOS is CalVer ( Folding the check result into a What I'd suggest instead: keep this as a small read-only check result (happy to rename it If you do want the enum/semver route, could you sketch how |
It already does work as our comparison basis 😆.. asic-rs/asic-rs-firmwares/braiins/src/backends/mod.rs Lines 24 to 35 in 548fdf8 asic-rs/asic-rs-firmwares/braiins/src/firmware.rs Lines 113 to 141 in 548fdf8 We just append a
Not exactly what I meant. struct FirmwareStats {
current_version: Option<SemVer>,
latest_version: Option<SemVer>,
firmware: Option<FirmwareUpdate>
}
impl FirmwareStats {
fn update_available {
// compare current to latest
...
}
}
enum FirmwareUpdate {
Local(FirmwareImage),
Remote(URL)
} |
…mwareUpdate enum
Per review: separate the version comparison from the update source, and compare
real versions instead of string inequality.
- FirmwareUpdate struct -> FirmwareStats { current_version, latest_version:
Option<semver::Version>, firmware: Option<FirmwareUpdate> }
- update_available() derived by comparing versions (was a stored bool computed
from string inequality, which flagged updates even for older "latest")
- new enum FirmwareUpdate { Local(FirmwareImage), Remote(String) } for the
update source; drop non-actionable release_date
- braiins v26_04: parse versions via shared parse_bos_version helper (extracted
from get_version), map release url -> Remote
- python: FirmwareStats pyclass with str version getters, PyFirmwareUpdate
mirror enum; .pyi updated
|
Done in
You were right on the version point — the One note: nothing populates CI green (Cargo + Python). |
Adds an on-demand "is newer firmware available?" check, separate from the telemetry poll (it hits the vendor's release server) — a UI can call it on a slow cadence (e.g. an HA
updateentity, ~daily) instead of every poll.FirmwareUpdateresult (current/latest version,update_available, release date/url) fromUpgradeFirmware::check_firmware_update(default: unsupported).bos.checkForUpgrade+bos.info.versionover the authenticated GraphQL client — a fully local check.Miner.check_firmware_update()+supports_check_firmware_update.VNish — how its GUI does it, and an open question. VNish works differently: it shows the installed version locally, but "are you up to date?" compares that against the vendor's cloud changelog —
GET partner.anthill.farm/api/client/releases-notesreturns a list of releases (series/version/stage), and the UI marks the latest stable vs. what's installed. There is no local API field for update-availability, so covering VNish means the lib making an external vendor-cloud call, unlike BraiinsOS's local check.On our side (a Home Assistant integration alpha) we'd surface the VNish installed version there and could do the cloud comparison consumer-side. But we could also imagine putting it in the lib so
check_firmware_updateis uniform across firmwares. What's your preference — should a vendor-cloud lookup like VNish's live in asic-rs, or stay on the consumer side? I kept this PR to the local BraiinsOS check; happy to add VNish whichever way you'd like.