use anyhow::Context as _;
use chrono::{DateTime, Local, NaiveDateTime, TimeZone as _, Utc};
use serde::{Deserialize, Serialize};
use crate::responses::TapoResponseExt;
use crate::utils::der_tapo_datetime_format;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass(from_py_object, get_all))]
pub struct EnergyDataResult {
pub local_time: NaiveDateTime,
pub start_date_time: DateTime<Utc>,
pub entries: Vec<EnergyDataIntervalResult>,
pub interval_length: u64,
}
impl TapoResponseExt for EnergyDataResult {}
#[cfg(feature = "python")]
crate::impl_to_dict!(EnergyDataResult);
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass(from_py_object, get_all))]
pub struct EnergyDataIntervalResult {
pub start_date_time: DateTime<Utc>,
pub energy: u64,
}
#[cfg(feature = "python")]
crate::impl_to_dict!(EnergyDataIntervalResult);
#[derive(Debug, Deserialize)]
pub(crate) struct EnergyDataResultRaw {
#[serde(deserialize_with = "der_tapo_datetime_format")]
pub local_time: NaiveDateTime,
pub data: Vec<u64>,
pub start_timestamp: i64,
pub interval: u64,
}
impl TapoResponseExt for EnergyDataResultRaw {}
impl TryInto<EnergyDataResult> for EnergyDataResultRaw {
type Error = crate::error::Error;
fn try_into(self) -> Result<EnergyDataResult, Self::Error> {
let mut entries = Vec::with_capacity(self.data.len());
let mut local_date_time = Local
.timestamp_opt(self.start_timestamp, 0)
.single()
.context("Failed to map start_timestamp to local time")?;
let start_date_time = local_date_time.to_utc();
for energy in self.data {
entries.push(EnergyDataIntervalResult {
start_date_time: local_date_time.to_utc(),
energy,
});
local_date_time = match self.interval {
60 => Ok(local_date_time + chrono::Duration::hours(1)),
1440 => Ok(local_date_time + chrono::Duration::days(1)),
43200 => Ok(local_date_time + chrono::Months::new(1)),
_ => Err(anyhow::anyhow!(
"Unsupported interval duration: {} minutes",
self.interval
)),
}?;
}
Ok(EnergyDataResult {
local_time: self.local_time,
start_date_time,
entries,
interval_length: self.interval,
})
}
}