use std::{collections::HashMap, fmt::Display};
use jiff::civil::{Date, Time};
use serde::{Serialize, Serializer};
use serde_repr::Serialize_repr;
use crate::types::Conditions;
#[derive(Debug, Serialize, Clone, Default)]
pub struct GetStatusParams {
#[serde(rename = "d", serialize_with = "jiff_ymd")]
pub date: Option<Date>,
#[serde(rename = "t", serialize_with = "jiff_hhmm")]
pub time: Option<Time>,
#[serde(rename = "asc", serialize_with = "bool_int")]
pub ascending: bool,
pub limit: Option<u16>,
#[serde(serialize_with = "jiff_hhmm")]
pub from: Option<Time>,
#[serde(serialize_with = "jiff_hhmm")]
pub to: Option<Time>,
#[serde(rename = "ext", serialize_with = "bool_int")]
pub extended_data: bool,
#[serde(rename = "sid1")]
pub system_id: Option<u32>,
}
#[derive(Debug, Serialize, Clone, Default)]
pub(crate) struct GetStatusParamsOuter {
#[serde(flatten)]
pub params: GetStatusParams,
#[serde(serialize_with = "bool_int")]
pub h: bool,
#[serde(serialize_with = "bool_int")]
pub stats: bool,
}
impl GetStatusParamsOuter {
pub const fn new(params: GetStatusParams, h: bool, stats: bool) -> Self { Self { params, h, stats } }
}
#[derive(Debug, Serialize, Clone, Default)]
pub struct GetStatisticsParams {
#[serde(rename = "df")]
pub date_from: Option<Date>,
#[serde(rename = "dt")]
pub date_to: Option<Date>,
#[serde(rename = "c", serialize_with = "bool_int")]
pub consumption: bool,
#[serde(rename = "crdr", serialize_with = "bool_int")]
pub credit_and_debit: bool,
#[serde(rename = "sid1")]
pub system_id: Option<u32>,
}
#[derive(Debug, Serialize, Clone, Default)]
#[allow(clippy::struct_excessive_bools)]
pub struct GetSystemParams {
#[serde(rename = "array2", serialize_with = "bool_int")]
pub secondary_array: bool,
#[serde(serialize_with = "bool_int")]
pub tariffs: bool,
#[serde(serialize_with = "bool_int")]
pub teams: bool,
#[serde(rename = "est", serialize_with = "bool_int")]
pub monthly_estimates: bool,
#[serde(serialize_with = "bool_int")]
pub donations: bool,
pub system_id: Option<u32>,
#[serde(rename = "ext", serialize_with = "bool_int")]
pub extended_data: bool,
}
impl GetSystemParams {
#[must_use]
pub const fn all() -> Self {
Self {
secondary_array: true,
tariffs: true,
teams: true,
monthly_estimates: true,
donations: true,
system_id: None,
extended_data: true,
}
}
#[must_use]
pub const fn all_for_system(system: u32) -> Self {
Self {
system_id: Some(system),
..Self::all()
}
}
}
#[derive(Debug, Serialize, Clone, Default)]
pub struct GetOutputParams {
#[serde(rename = "df", serialize_with = "jiff_ymd")]
pub date_from: Option<Date>,
#[serde(rename = "dt", serialize_with = "jiff_ymd")]
pub date_to: Option<Date>,
pub limit: Option<u8>,
#[serde(rename = "sid1")]
pub system_id: Option<u32>,
#[serde(serialize_with = "bool_int")]
pub insolation: bool,
#[serde(rename = "timeofexport", serialize_with = "bool_int")]
pub time_of_export: bool,
}
#[derive(Copy, Clone, Debug, Serialize, PartialEq, Eq, Hash)]
pub enum Aggregation {
#[serde(rename = "m")]
Monthly,
#[serde(rename = "y")]
Yearly,
}
#[derive(Debug, Serialize, Clone, Default)]
pub(crate) struct GetOutputParamsOuter {
#[serde(flatten)]
pub params: GetOutputParams,
pub a: Option<Aggregation>,
pub tid: Option<u32>,
}
#[derive(Debug, Serialize, Clone, Default)]
pub struct GetExtendedParams {
#[serde(rename = "df")]
pub date_from: Option<Date>,
#[serde(rename = "dt")]
pub date_to: Option<Date>,
pub limit: Option<u8>,
}
#[derive(Debug, Serialize, Clone, Default)]
pub struct GetInsolationParams {
#[serde(rename = "d", serialize_with = "jiff_ymd")]
pub date: Option<Date>,
#[serde(rename = "tz")]
pub timezone: Option<String>,
#[serde(rename = "ll", serialize_with = "lat_long")]
pub location: Option<(f32, f32)>,
#[serde(rename = "sid1")]
pub system_id: Option<u32>,
}
#[derive(Debug, Serialize, Clone)]
pub struct SearchParams {
#[serde(rename = "q")]
pub query: String,
#[serde(rename = "ll", serialize_with = "lat_long")]
pub location: Option<(f32, f32)>,
#[serde(rename = "country", serialize_with = "bool_int")]
pub country_names: bool,
pub country_code: Option<CountryCode>,
pub seen: Option<u32>,
}
impl SearchParams {
pub fn new(query: impl Into<String>) -> Self {
Self {
query: query.into(),
location: None,
country_names: false,
country_code: None,
seen: None,
}
}
}
#[derive(Debug, Serialize, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CountryCode {
#[serde(rename = "au")]
Australia,
#[serde(rename = "be")]
Belgium,
#[serde(rename = "dk")]
Denmark,
#[serde(rename = "it")]
Italy,
#[serde(rename = "nl")]
Netherlands,
#[serde(rename = "uk")]
UnitedKingdom,
#[serde(rename = "us")]
UnitedStates,
}
#[derive(Serialize, Clone, Debug)]
pub struct AddOutputParams {
#[serde(serialize_with = "jiff_ymd_direct")]
pub date: Date,
pub generated: Option<u32>,
pub exported: Option<u32>,
pub peak: Option<u32>,
#[serde(serialize_with = "jiff_hhmm")]
pub peak_time: Option<Time>,
pub conditions: Option<Conditions>,
pub min_temp: Option<f32>,
pub max_temp: Option<f32>,
pub comment: Option<String>,
pub import_peak: Option<u32>,
pub import_off_peak: Option<u32>,
pub import_shoulder: Option<u32>,
pub import_high_shoulder: Option<u32>,
pub consumption: Option<u32>,
pub export_peak: Option<u32>,
pub export_off_peak: Option<u32>,
pub export_shoulder: Option<u32>,
pub export_high_shoulder: Option<u32>,
}
impl AddOutputParams {
#[must_use]
pub const fn new(date: Date) -> Self {
Self {
date,
generated: None,
exported: None,
peak: None,
peak_time: None,
conditions: None,
min_temp: None,
max_temp: None,
comment: None,
import_peak: None,
import_off_peak: None,
import_shoulder: None,
import_high_shoulder: None,
consumption: None,
export_peak: None,
export_off_peak: None,
export_shoulder: None,
export_high_shoulder: None,
}
}
}
#[allow(clippy::too_long_first_doc_paragraph)]
#[derive(Clone, Debug, Serialize)]
pub struct AddStatusCommon {
#[serde(rename = "d", serialize_with = "jiff_ymd_direct")]
pub date: Date,
#[serde(rename = "t", serialize_with = "jiff_hhmm_direct")]
pub time: Time,
#[serde(rename = "v1")]
pub energy_generation: Option<u32>,
#[serde(rename = "v2")]
pub power_generation: Option<i32>,
#[serde(rename = "v3")]
pub energy_consumption: Option<u32>,
#[serde(rename = "v4")]
pub power_consumption: Option<i32>,
#[serde(rename = "v5")]
pub temperature: Option<f32>,
#[serde(rename = "v6")]
pub voltage: Option<f32>,
}
impl AddStatusCommon {
#[must_use]
pub const fn new(date: Date, time: Time) -> Self {
Self {
date,
time,
energy_generation: None,
power_generation: None,
energy_consumption: None,
power_consumption: None,
temperature: None,
voltage: None,
}
}
}
#[derive(Clone, Debug, Serialize, Default)]
pub struct AddExtendedParams {
#[serde(rename = "v7")]
pub extended_value_1: Option<f32>,
#[serde(rename = "v8")]
pub extended_value_2: Option<f32>,
#[serde(rename = "v9")]
pub extended_value_3: Option<f32>,
#[serde(rename = "v10")]
pub extended_value_4: Option<f32>,
#[serde(rename = "v11")]
pub extended_value_5: Option<f32>,
#[serde(rename = "v12")]
pub extended_value_6: Option<f32>,
}
#[derive(Clone, Debug, Serialize)]
pub struct AddStatusParams {
#[serde(flatten)]
pub common: AddStatusCommon,
#[serde(rename = "c1")]
pub cumulative_flag: CumulativeFlag,
#[serde(rename = "n", serialize_with = "bool_int")]
pub net_data: bool,
#[serde(flatten)]
pub extended_data: Option<AddExtendedParams>,
#[serde(rename = "m1")]
pub message: Option<String>,
#[serde(flatten)]
pub battery: Option<AddBatteryParams>,
}
impl AddStatusParams {
#[must_use]
pub const fn new(common: AddStatusCommon) -> Self {
Self {
common,
cumulative_flag: CumulativeFlag::False,
net_data: false,
extended_data: None,
message: None,
battery: None,
}
}
}
impl From<AddStatusCommon> for AddStatusParams {
fn from(common: AddStatusCommon) -> Self { Self::new(common) }
}
#[derive(Clone, Debug, Serialize, Default)]
pub struct AddBatteryParams {
#[serde(rename = "b1")]
pub power: i32,
#[serde(rename = "b2")]
pub state_of_charge: Option<f32>,
#[serde(rename = "b3")]
pub size: Option<u32>,
#[serde(rename = "b4")]
pub lifetime_charge: Option<u32>,
#[serde(rename = "b5")]
pub lifetime_discharge: Option<u32>,
#[serde(rename = "b6")]
pub state: Option<BatteryState>,
}
#[derive(Copy, Clone, Debug, Default, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize_repr)]
#[repr(u8)]
pub enum BatteryState {
Invalid,
#[default]
Standby,
ThermalManagement,
Enabled,
Fault,
UserDefinedA,
UserDefinedB,
UserDefinedC,
UserDefinedD,
UserDefinedE,
}
#[derive(Clone, Debug, Serialize)]
pub struct AddBatchStatusParams {
#[serde(flatten)]
pub common: AddStatusCommon,
#[serde(flatten)]
pub extended_data: Option<AddExtendedParams>,
}
impl AddBatchStatusParams {
#[must_use]
pub const fn new(common: AddStatusCommon, extended_data: Option<AddExtendedParams>) -> Self {
Self { common, extended_data }
}
}
impl From<AddStatusCommon> for AddBatchStatusParams {
fn from(common: AddStatusCommon) -> Self {
Self {
common,
extended_data: None,
}
}
}
#[derive(Clone, Debug, Serialize)]
pub struct AddNetBatchStatusParams {
#[serde(serialize_with = "jiff_ymd_direct")]
pub date: Date,
#[serde(serialize_with = "jiff_hhmm_direct")]
pub time: Time,
spacer_a: (),
pub power_exported: u32,
spacer_b: (),
pub power_imported: u32,
}
impl AddNetBatchStatusParams {
#[must_use]
pub const fn new(date: Date, time: Time, power_exported: u32, power_imported: u32) -> Self {
Self {
date,
time,
spacer_a: (),
power_exported,
spacer_b: (),
power_imported,
}
}
}
#[derive(Clone, Debug, Copy, Default, Serialize, Hash, Eq, PartialEq)]
pub enum CumulativeFlag {
#[serde(rename = "0")]
#[default]
False,
#[serde(rename = "1")]
Both,
#[serde(rename = "2")]
Generation,
#[serde(rename = "3")]
Consumption,
}
#[derive(Clone, Debug, Default)]
pub struct PostSystemParams {
pub name: Option<String>,
pub(crate) extended_variables: HashMap<ExtendedVariable, ExtendedVariableUpdate>,
}
impl PostSystemParams {
#[must_use]
pub fn new() -> Self { Self::default() }
#[must_use]
pub fn new_rename(name: String) -> Self {
Self {
name: Some(name),
extended_variables: HashMap::new(),
}
}
pub fn add_update(&mut self, variable: ExtendedVariable, update: ExtendedVariableUpdate) -> &mut Self {
self.extended_variables.insert(variable, update);
self
}
#[must_use]
pub fn get_update(&self, variable: ExtendedVariable) -> Option<&ExtendedVariableUpdate> {
self.extended_variables.get(&variable)
}
}
#[derive(Debug, Clone, Default)]
pub struct ExtendedVariableUpdate {
pub label: Option<String>,
pub unit: Option<String>,
pub colour: Option<String>,
pub axis: Option<u8>,
pub graph: Option<Graph>,
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum ExtendedVariable {
V7 = 7,
V8 = 8,
V9 = 9,
V10 = 10,
V11 = 11,
V12 = 12,
}
impl TryFrom<u8> for ExtendedVariable {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
7 => Ok(Self::V7),
8 => Ok(Self::V8),
9 => Ok(Self::V9),
10 => Ok(Self::V10),
11 => Ok(Self::V11),
12 => Ok(Self::V12),
_ => Err(value),
}
}
}
#[derive(Copy, Clone, Debug, Default, Serialize, Hash, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum Graph {
Area,
#[default]
Line,
}
impl Display for Graph {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Area => write!(f, "area"),
Self::Line => write!(f, "line"),
}
}
}
#[derive(Serialize)]
pub(crate) struct DeleteStatusParams {
#[serde(serialize_with = "jiff_ymd_direct")]
pub d: Date,
#[serde(serialize_with = "jiff_hhmm")]
pub t: Option<Time>,
}
#[allow(clippy::ref_option)]
fn jiff_ymd<S>(value: &Option<Date>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(value) = value {
s.serialize_str(value.strftime("%Y%m%d").to_string().as_str())
} else {
s.serialize_none()
}
}
#[allow(clippy::ref_option)]
fn jiff_ymd_direct<S>(value: &Date, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
jiff_ymd(&Some(*value), s)
}
#[allow(clippy::ref_option)]
fn jiff_hhmm<S>(value: &Option<Time>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(value) = value {
s.serialize_str(value.strftime("%H:%M").to_string().as_str())
} else {
s.serialize_none()
}
}
#[allow(clippy::ref_option)]
fn jiff_hhmm_direct<S>(value: &Time, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
jiff_hhmm(&Some(*value), s)
}
#[allow(clippy::trivially_copy_pass_by_ref)]
fn bool_int<S>(value: &bool, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_u8(u8::from(*value))
}
#[allow(clippy::ref_option)]
fn lat_long<S>(value: &Option<(f32, f32)>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(value) = value {
s.serialize_str(format!("{},{}", value.0, value.1).as_str())
} else {
s.serialize_none()
}
}