Use type-based data collections

This commit is contained in:
Xiretza 2024-02-02 14:31:20 +00:00
parent 97f7a5f1e2
commit 15d9d21c9b
3 changed files with 31 additions and 41 deletions

1
Cargo.lock generated
View file

@ -176,6 +176,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"reqwest", "reqwest",
"serde", "serde",
"serde_json",
"strum_macros", "strum_macros",
"time", "time",
] ]

View file

@ -10,3 +10,4 @@ serde = { version = "1.0", features = ["derive"]}
reqwest = { version = "0.11", features = ["blocking", "json"]} reqwest = { version = "0.11", features = ["blocking", "json"]}
strum_macros = { version = "0.26.1"} strum_macros = { version = "0.26.1"}
time = { version = "0.3.32", features = ["serde", "serde-well-known"]} time = { version = "0.3.32", features = ["serde", "serde-well-known"]}
serde_json = "1.0.113"

View file

@ -1,4 +1,4 @@
use serde::{Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::net::IpAddr; use std::net::IpAddr;
#[derive(Debug)] #[derive(Debug)]
@ -91,14 +91,6 @@ pub fn get_api_version(ip: IpAddr) -> Result<ApiVersion, Box<dyn std::error::Err
Ok(reqwest::blocking::Client::new().get(url).send()?.json()?) Ok(reqwest::blocking::Client::new().get(url).send()?.json()?)
} }
pub enum Scope {
System,
Device {
device_id: DeviceId,
data_collection: DataCollection,
},
}
pub struct DeviceId(u8); pub struct DeviceId(u8);
impl TryFrom<u8> for DeviceId { impl TryFrom<u8> for DeviceId {
@ -119,46 +111,42 @@ impl From<DeviceId> for u8 {
} }
} }
#[derive(strum_macros::Display)] pub trait DataCollection: DeserializeOwned {
pub enum DataCollection { /// Returns the value of the `DataCollection` GET parameter for this collection.
CumulationInverterData, fn param_value() -> &'static str;
CommonInverterData,
ThreePInverterData,
MinMaxInverterData,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct CumulationInverterData<T> { pub struct CumulationInverterData {
pac: T, pac: UnitAndValue<u64>,
day_energy: T, day_energy: UnitAndValue<f64>,
year_energy: T, year_energy: UnitAndValue<f64>,
total_energy: T, total_energy: UnitAndValue<f64>,
device_status: Option<std::collections::HashMap<String, String>>, #[serde(rename = "DeviceStatus")]
device_status: Option<HashMap<String, serde_json::Value>>,
} }
pub fn get_inverter_realtime_data( impl DataCollection for CumulationInverterData {
ip: IpAddr, fn param_value() -> &'static str {
scope: Scope, "CumulationInverterData"
) -> Result<FroniousResponse, Box<dyn std::error::Error>> {
let mut params: Vec<(&str, String)> = vec![];
match scope {
Scope::System => {
params.push(("Scope", "System".to_owned()));
}
Scope::Device {
device_id,
data_collection,
} => {
params.push(("Scope", "Device".to_owned()));
params.push(("DeviceId", (u8::from(device_id)).to_string()));
params.push(("DataCollection", data_collection.to_string()));
}
} }
}
pub fn get_inverter_realtime_data_device<C: DataCollection>(
ip: IpAddr,
device_id: DeviceId,
) -> Result<FroniousResponse<CommonResponseBody<CumulationInverterData>>, Box<dyn std::error::Error>>
{
let device_id = u8::from(device_id).to_string();
let params = [
("Scope", "Device"),
("DeviceId", &device_id),
("DataCollection", C::param_value()),
];
let mut url = reqwest::Url::parse_with_params( let mut url = reqwest::Url::parse_with_params(
&format!("http://placeholder.local/solar_api/v1/GetInverterRealtimeData.cgi"), "http://placeholder.local/solar_api/v1/GetInverterRealtimeData.cgi",
&params, &params,
)?; )?;
let _ = url.set_ip_host(ip); let _ = url.set_ip_host(ip);