Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions asic-rs-core/src/config/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum ConfigField {
Tuning,
Fan,
Temperature,
Timezone,
}

/// A function pointer type that takes a JSON `Value` and an optional key,
Expand Down
1 change: 1 addition & 0 deletions asic-rs-core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ pub mod fan;
pub mod pools;
pub mod scaling;
pub mod temperature;
pub mod timezone;
pub mod tuning;
55 changes: 55 additions & 0 deletions asic-rs-core/src/config/timezone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#[cfg(feature = "python")]
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};

#[cfg_attr(
feature = "python",
pyclass(skip_from_py_object, get_all, module = "asic_rs")
)]
#[cfg_attr(feature = "python", asic_rs_pydantic::py_pydantic_model)]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
/// Timezone configuration.
pub struct TimezoneConfig {
/// The configured timezone (a named IANA zone on BraiinsOS, or a fixed UTC offset like "GMT+1" on VNish).
pub timezone: Option<String>,
/// The timezones the miner accepts (named zones where available; may be a default fallback list).
pub available: Vec<String>,
}

#[cfg(feature = "python")]
#[pymethods]
impl TimezoneConfig {
#[new]
#[pyo3(signature = (timezone = None, available = None))]
fn py_new(timezone: Option<String>, available: Option<Vec<String>>) -> Self {
Self {
timezone,
available: available.unwrap_or_default(),
}
}
}

#[cfg(feature = "python")]
mod python_impls {
use asic_rs_pydantic::get_optional_field;
use pyo3::{Borrowed, PyAny, PyErr, PyResult, conversion::FromPyObject, types::PyAnyMethods};

use super::TimezoneConfig;

impl FromPyObject<'_, '_> for TimezoneConfig {
type Error = PyErr;

fn extract(obj: Borrowed<'_, '_, PyAny>) -> PyResult<Self> {
Ok(TimezoneConfig {
timezone: get_optional_field(&obj, "timezone")?
.map(|value| value.extract())
.transpose()?
.flatten(),
available: get_optional_field(&obj, "available")?
.map(|value| value.extract())
.transpose()?
.unwrap_or_default(),
})
}
}
}
30 changes: 29 additions & 1 deletion asic-rs-core/src/traits/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::{
pools::PoolGroupConfig,
scaling::ScalingConfig,
temperature::TemperatureConfig,
timezone::TimezoneConfig,
tuning::TuningConfig,
},
data::{
Expand Down Expand Up @@ -87,6 +88,7 @@ pub trait SupportsConfigs:
+ SupportsTemperatureConfig
+ SupportsTuningConfig
+ SupportsFanConfig
+ SupportsTimezoneConfig
{
}

Expand All @@ -96,7 +98,8 @@ impl<
+ SupportsScalingConfig
+ SupportsTemperatureConfig
+ SupportsTuningConfig
+ SupportsFanConfig,
+ SupportsFanConfig
+ SupportsTimezoneConfig,
> SupportsConfigs for T
{
}
Expand Down Expand Up @@ -950,6 +953,31 @@ pub trait SupportsTemperatureConfig: CollectConfigs {
}
}

#[async_trait]
pub trait SupportsTimezoneConfig: CollectConfigs {
#[allow(unused_variables)]
async fn set_timezone_config(&self, config: TimezoneConfig) -> anyhow::Result<bool> {
anyhow::bail!("Setting timezone config is not supported on this platform");
}
#[tracing::instrument(level = "debug")]
async fn get_timezone_config(&self) -> anyhow::Result<TimezoneConfig> {
let mut collector = self.get_config_collector();
let data = collector.collect(&[ConfigField::Timezone]).await;
self.parse_timezone_config(&data)
}
#[allow(unused_variables)]
fn parse_timezone_config(
&self,
data: &HashMap<ConfigField, Value>,
) -> anyhow::Result<TimezoneConfig> {
anyhow::bail!("Getting timezone config is not supported on this platform");
}

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

#[async_trait]
pub trait SupportsTuningConfig: CollectConfigs {
#[allow(unused_variables)]
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/antminer/src/backends/v2020/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,7 @@ impl GetFluidTemperature for AntMinerV2020 {

impl GetPsuFans for AntMinerV2020 {}
impl GetTuningCapabilities for AntMinerV2020 {}
impl SupportsTimezoneConfig for AntMinerV2020 {}

impl GetMessages for AntMinerV2020 {
fn parse_messages(&self, data: &HashMap<DataField, Value>) -> Vec<MinerMessage> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/antminer/src/backends/v2023_07/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ impl GetFluidTemperature for AntMinerV202307 {

impl GetPsuFans for AntMinerV202307 {}
impl GetTuningCapabilities for AntMinerV202307 {}
impl SupportsTimezoneConfig for AntMinerV202307 {}

impl GetMessages for AntMinerV202307 {
fn parse_messages(&self, data: &HashMap<DataField, Value>) -> Vec<MinerMessage> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/auradine/src/backends/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,7 @@ impl GetPsuFans for AuradineV1 {
}

impl GetFluidTemperature for AuradineV1 {}
impl SupportsTimezoneConfig for AuradineV1 {}

impl GetWattage for AuradineV1 {
fn parse_wattage(&self, data: &HashMap<DataField, Value>) -> Option<Power> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/avalonminer/src/backends/avalon_a/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ impl GetControlBoardVersion for AvalonAMiner {
}

impl GetHostname for AvalonAMiner {}
impl SupportsTimezoneConfig for AvalonAMiner {}

impl GetApiVersion for AvalonAMiner {
fn parse_api_version(&self, data: &HashMap<DataField, Value>) -> Option<String> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/avalonminer/src/backends/avalon_q/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ impl GetMAC for AvalonQMiner {
}

impl GetSerialNumber for AvalonQMiner {}
impl SupportsTimezoneConfig for AvalonQMiner {}

impl GetHostname for AvalonQMiner {}

Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/bitaxe/src/backends/v2_0_0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ impl UpgradeFirmware for Bitaxe200 {
}

impl HasAuth for Bitaxe200 {}
impl SupportsTimezoneConfig for Bitaxe200 {}
impl HasDefaultAuth for Bitaxe200 {}

#[async_trait]
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/bitaxe/src/backends/v2_9_0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ impl UpgradeFirmware for Bitaxe290 {
}

impl HasAuth for Bitaxe290 {}
impl SupportsTimezoneConfig for Bitaxe290 {}
impl HasDefaultAuth for Bitaxe290 {}

#[async_trait]
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/braiins/src/backends/v21_09/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ impl GetTuningCapabilities for BraiinsV2109 {
Some(power_target_capabilities(power_target))
}
}
impl SupportsTimezoneConfig for BraiinsV2109 {}

impl GetHashboards for BraiinsV2109 {
fn parse_hashboards(&self, data: &HashMap<DataField, Value>) -> Vec<BoardData> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/braiins/src/backends/v25_03/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ impl GetTuningCapabilities for BraiinsV2503 {
Some(power_target_capabilities(power_target))
}
}
impl SupportsTimezoneConfig for BraiinsV2503 {}

impl GetHashboards for BraiinsV2503 {
fn parse_hashboards(&self, data: &HashMap<DataField, Value>) -> Vec<BoardData> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/braiins/src/backends/v25_05/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ impl GetTuningCapabilities for BraiinsV2505 {
Some(power_target_capabilities(power_target))
}
}
impl SupportsTimezoneConfig for BraiinsV2505 {}

impl GetHashboards for BraiinsV2505 {
fn parse_hashboards(&self, data: &HashMap<DataField, Value>) -> Vec<BoardData> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/braiins/src/backends/v25_07/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ impl GetTuningCapabilities for BraiinsV2507 {
Some(tuner_constraints_capabilities(tuner))
}
}
impl SupportsTimezoneConfig for BraiinsV2507 {}

impl GetPsuFans for BraiinsV2507 {}

Expand Down
71 changes: 69 additions & 2 deletions asic-rs-firmwares/braiins/src/backends/v26_04/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use std::{collections::HashMap, net::IpAddr, str::FromStr, time::Duration};
use anyhow;
use asic_rs_core::{
config::{
collector::{ConfigCollector, ConfigField, ConfigLocation},
collector::{ConfigCollector, ConfigExtractor, ConfigField, ConfigLocation},
pools::PoolGroupConfig,
timezone::TimezoneConfig,
},
data::{
board::{BoardData, MinerControlBoard},
Expand Down Expand Up @@ -79,7 +80,20 @@ impl APIClient for BraiinsV2604 {
impl GetConfigsLocations for BraiinsV2604 {
#[allow(unused_variables)]
fn get_configs_locations(&self, data_field: ConfigField) -> Vec<ConfigLocation> {
vec![]
const GQL_TIMEZONE: MinerCommand = MinerCommand::GraphQL {
command: "{ bos { timezone { id } timezoneList { id } } }",
};
match data_field {
ConfigField::Timezone => vec![(
GQL_TIMEZONE,
ConfigExtractor {
func: get_by_pointer,
key: Some("/bos"),
tag: None,
},
)],
_ => vec![],
}
}
}

Expand Down Expand Up @@ -634,6 +648,59 @@ impl GetTuningCapabilities for BraiinsV2604 {
}
}

#[async_trait]
impl SupportsTimezoneConfig for BraiinsV2604 {
fn supports_timezone_config(&self) -> bool {
true
}

fn parse_timezone_config(
&self,
data: &HashMap<ConfigField, Value>,
) -> anyhow::Result<TimezoneConfig> {
let obj = data
.get(&ConfigField::Timezone)
.ok_or_else(|| anyhow::anyhow!("No timezone data returned"))?;
let timezone = obj
.pointer("/timezone/id")
.and_then(|v| v.as_str())
.map(String::from);
let available = obj
.pointer("/timezoneList")
.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|t| t.get("id").and_then(|v| v.as_str()).map(String::from))
.collect()
})
.unwrap_or_default();
Ok(TimezoneConfig {
timezone,
available,
})
}

async fn set_timezone_config(&self, config: TimezoneConfig) -> anyhow::Result<bool> {
let timezone = match config.timezone {
Some(tz) => tz,
None => anyhow::bail!("Timezone config has no timezone to set"),
};
let mutation = r#"mutation ($tz: String!) {
bos { setTimezone(timezone: $tz) { __typename } }
}"#;
let variables = json!({ "tz": timezone });
let result = self
.graphql
.send_graphql_command(mutation, true, Some(variables))
.await?;
// BosResult is a union; a `BosError` variant signals failure.
let typename = result
.pointer("/bos/setTimezone/__typename")
.and_then(|v| v.as_str());
Ok(matches!(typename, Some(t) if t != "BosError"))
}
}

impl GetPsuFans for BraiinsV2604 {}

impl GetMessages for BraiinsV2604 {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/epic/src/backends/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ impl GetFans for PowerPlayV1 {

impl GetPsuFans for PowerPlayV1 {}
impl GetTuningCapabilities for PowerPlayV1 {}
impl SupportsTimezoneConfig for PowerPlayV1 {}

impl GetFluidTemperature for PowerPlayV1 {}

Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/futurebit/src/backends/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ impl GetFans for ApolloV2 {
}

impl GetPsuFans for ApolloV2 {}
impl SupportsTimezoneConfig for ApolloV2 {}

impl GetFluidTemperature for ApolloV2 {}

Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/luxminer/src/backends/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ impl GetTuningTarget for LuxMinerV1 {

impl GetScaledTuningTarget for LuxMinerV1 {}
impl GetTuningCapabilities for LuxMinerV1 {}
impl SupportsTimezoneConfig for LuxMinerV1 {}
impl GetPsuFans for LuxMinerV1 {}

impl GetMessages for LuxMinerV1 {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/marathon/src/backends/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ impl GetMAC for MaraV1 {
}

impl GetSerialNumber for MaraV1 {}
impl SupportsTimezoneConfig for MaraV1 {}

impl GetHostname for MaraV1 {
fn parse_hostname(&self, data: &HashMap<DataField, Value>) -> Option<String> {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/nerdaxe/src/backends/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ impl GetMAC for NerdAxeV1 {
}

impl GetSerialNumber for NerdAxeV1 {}
impl SupportsTimezoneConfig for NerdAxeV1 {}
impl GetHostname for NerdAxeV1 {
fn parse_hostname(&self, data: &HashMap<DataField, Value>) -> Option<String> {
data.extract::<String>(DataField::Hostname)
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/proto/src/backends/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ impl GetFans for ProtoV1 {
}

impl GetPsuFans for ProtoV1 {}
impl SupportsTimezoneConfig for ProtoV1 {}
impl GetFluidTemperature for ProtoV1 {}

impl GetWattage for ProtoV1 {
Expand Down
1 change: 1 addition & 0 deletions asic-rs-firmwares/sealminer/src/backends/v2025/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ impl GetSerialNumber for SealMinerV2025 {
}

impl GetHostname for SealMinerV2025 {}
impl SupportsTimezoneConfig for SealMinerV2025 {}

impl GetApiVersion for SealMinerV2025 {
fn parse_api_version(&self, data: &HashMap<DataField, Value>) -> Option<String> {
Expand Down
Loading