Skip to content

Commit

Permalink
Wrk - Mostly added a bunch of messages (#11)
Browse files Browse the repository at this point in the history
Clippy pedantic
Added site power request message.
Addeded site_data_period.
Added site_energy request and response.
Added SiteTimeFrameEnergy request.
Check response status before trying to parse json.
Added SitePowerReq/Resp.
Added SiteList request / response.
Added site_overview.
Added site_power_flow.
Added site_storage_data.
Added site_environmental_benefits.
  • Loading branch information
grtwje authored May 23, 2022
1 parent 68e97d0 commit 616b202
Show file tree
Hide file tree
Showing 26 changed files with 1,423 additions and 135 deletions.
15 changes: 6 additions & 9 deletions src/current_version.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
//! Module for querying the current API version of the SolarEdge monitoring server.
use crate::{SendReq, SolaredgeCredentials, MONITORING_API_URL};
use serde::{Deserialize, Serialize};
use crate::{SendReq, MONITORING_API_URL};
use serde::Deserialize;

/// Current version request
#[derive(Clone, Debug, PartialEq)]
pub struct Req;

/// Current version response
#[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq)]
#[derive(Clone, Deserialize, Debug, Default, PartialEq)]
pub struct Resp {
/// The API version running on the server
pub version: Version,
}

/// The release version of the server
#[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq)]
#[derive(Clone, Deserialize, Debug, Default, PartialEq)]
pub struct Version {
/// The release number running on the server in <major.minor.revision> format.
pub release: String,
Expand All @@ -30,11 +30,8 @@ impl Req {
}

impl SendReq<Resp> for Req {
fn build_url(&self, solaredge: &SolaredgeCredentials) -> String {
format!(
"{}version/current?{}",
*MONITORING_API_URL, solaredge.api_key,
)
fn build_url(&self, _: &str, api_key: &str) -> String {
format!("{}version/current?{}", *MONITORING_API_URL, api_key,)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/date_value.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! Module for handling generic date / value pairs returned by the SolarEdge server monitoring API.
use serde::{Deserialize, Serialize};
use serde::Deserialize;

/// A date and value pair returned from the monitoring API. The value units are specified by the unit
/// field elsewhere in the response.
#[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq)]
#[derive(Clone, Deserialize, Debug, Default, PartialEq)]
pub struct DateValue {
/// YYYY-mm-dd HH:MM:SS
pub date: String,
Expand Down
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ impl Error {
pub enum Kind {
/// An error returned from the reqwest crate.
ReqwestError(reqwest::Error),

/// HTTP error from sending a request.
HttpErrorStatus(String, String),
}

impl error::Error for Error {
fn description(&self) -> &str {
match self.kind {
Kind::ReqwestError(_) => "Reqwest error",
Kind::HttpErrorStatus(_, _) => "HTTP error",
}
}
}
Expand All @@ -42,6 +46,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.kind {
Kind::ReqwestError(s) => write!(f, "Reqwest Error: HTTP status-code{}", s),
Kind::HttpErrorStatus(s, t) => write!(f, "HTTP error: {}: {}", s, t),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/meter_type.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Module for specifying the meter type in SolarEdge server monitoring API requests and responses.
use serde::{Deserialize, Serialize};
use serde::Deserialize;

/// Meters supported by SolarEdge.
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
#[derive(Clone, Deserialize, Debug, PartialEq)]
pub enum MeterType {
/// Solar energy produced.
Production,
Expand Down
7 changes: 3 additions & 4 deletions src/meter_value.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
//! Module for holding values for a specified meter type in SolarEdge server monitoring API responses.
pub use crate::date_value::DateValue;
use crate::meter_type::MeterType;
use serde::{Deserialize, Serialize};
use crate::{DateValue, MeterType};
use serde::Deserialize;

/// Values for the meter type over a range of dates.
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
#[derive(Clone, Deserialize, Debug, PartialEq)]
pub struct MeterValue {
/// The meter type of the associated values.
#[serde(rename = "type")]
Expand Down
124 changes: 84 additions & 40 deletions src/se_ms_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,36 +37,31 @@
//!
//! Supported API requests/responses include:
//! * [CurrentVersionReq] / [CurrentVersionResp]
//! * [SiteDataPeriodReq] / [SiteDataPeriodResp]
//! * [SiteDetailsReq] / [SiteDetailsResp]
//! * [SiteEnergyReq] / [SiteEnergyResp]
//! * [SiteEnergyDetailedReq] / [SiteEnergyDetailedResp]
//! * [SiteEnvironmentalBenefitsReq] / [SiteEnvironmentalBenefitsResp]
//! * [SiteListReq] / [SiteListResp]
//! * [SiteOverviewReq] / [SiteOverviewResp]
//! * [SitePowerReq] / [SitePowerResp]
//! * [SitePowerDetailedReq] / [SitePowerDetailedResp]
//! * [SitePowerFlowReq] / [SitePowerFlowResp]
//! * [SiteStorageDataReq] / [SiteStorageDataResp]
//! * [SiteTimeFrameEnergyReq] / [SiteTimeFrameEnergyResp]
//! * [SupportedVersionsReq] / [SupportedVersionsResp]
//!
//! TODO:
//! SitesList,
//! SiteDataPeriod start/end dates,
//! SiteDataPeriod bulk,
//! SiteEnergy,
//! SiteEnergy bulk,
//! SiteTimeFrameEnergy,
//! SiteTimeFrameEnergy bulk,
//! SitePower,
//! SitePower bulk,
//! SiteOverview,
//! SiteOverview bulk,
//! SitePowerFlow,
//! SiteStorageInformation,
//! SiteImage,
//! SiteEnvironmentalBenefits,
//! SiteInstallerImage,
//! SiteEquipmentList,
//! SiteInventory,
//! SiteInverterTechnicalData,
//! SiteEquipmentChangeLog,
//! AccountsList,
//! SiteMetersData,
//! SiteSensorList,
//! SiteSensorData
//! * SiteImage,
//! * SiteInstallerImage,
//! * SiteEquipmentList,
//! * SiteInventory,
//! * SiteInverterTechnicalData,
//! * SiteEquipmentChangeLog,
//! * AccountsList,
//! * SiteMetersData,
//! * SiteSensorList,
//! * SiteSensorData
#![warn(unused_crate_dependencies)]
#![deny(unused_extern_crates)]
Expand All @@ -75,32 +70,57 @@
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::doc_markdown)]

pub use current_version::Req as CurrentVersionReq;
pub use current_version::Resp as CurrentVersionResp;
pub use current_version::{Req as CurrentVersionReq, Resp as CurrentVersionResp};
pub use site_data_period::{Req as SiteDataPeriodReq, Resp as SiteDataPeriodResp};
pub use site_details::{Req as SiteDetailsReq, Resp as SiteDetailsResp};
pub use site_energy::{Req as SiteEnergyReq, Resp as SiteEnergyResp};
pub use site_energy_detailed::{Req as SiteEnergyDetailedReq, Resp as SiteEnergyDetailedResp};
pub use site_environmental_benefits::{
Req as SiteEnvironmentalBenefitsReq, Resp as SiteEnvironmentalBenefitsResp,
};
pub use site_list::{Req as SiteListReq, Resp as SiteListResp};
pub use site_overview::{Req as SiteOverviewReq, Resp as SiteOverviewResp};
pub use site_power::{Req as SitePowerReq, Resp as SitePowerResp};
pub use site_power_detailed::{Req as SitePowerDetailedReq, Resp as SitePowerDetailedResp};
pub use site_power_flow::{Req as SitePowerFlowReq, Resp as SitePowerFlowResp};
pub use site_storage_data::{Req as SiteStorageDataReq, Resp as SiteStorageDataResp};
pub use site_time_frame_energy::{Req as SiteTimeFrameEnergyReq, Resp as SiteTimeFrameEnergyResp};
pub use supported_versions::{Req as SupportedVersionsReq, Resp as SupportedVersionsResp};

pub use date_value::DateValue;
pub use error::{Error, Kind};
pub use meter_type::MeterType;
pub use meter_value::MeterValue;
use serde::Deserialize;
pub use site_details::Req as SiteDetailsReq;
pub use site_details::Resp as SiteDetailsResp;
pub use site_energy_detailed::Req as SiteEnergyDetailedReq;
pub use site_energy_detailed::Resp as SiteEnergyDetailedResp;
pub use site_power_detailed::Req as SitePowerDetailedReq;
pub use site_power_detailed::Resp as SitePowerDetailedResp;
pub use supported_versions::Req as SupportedVersionsReq;
pub use supported_versions::Resp as SupportedVersionsResp;
pub use site_details::SiteDetails;
pub use site_location::SiteLocation;
pub use site_module::SiteModule;
pub use site_public_settings::SitePublicSettings;
pub use system_units::SystemUnits;
pub use time_unit::TimeUnit;

mod current_version;
mod date_value;
mod error;
mod meter_type;
mod meter_value;
mod site_data_period;
mod site_details;
mod site_energy;
mod site_energy_detailed;
mod site_environmental_benefits;
mod site_list;
mod site_location;
mod site_module;
mod site_overview;
mod site_power;
mod site_power_detailed;
mod site_power_flow;
mod site_public_settings;
mod site_storage_data;
mod site_time_frame_energy;
mod supported_versions;
mod system_units;
mod time_unit;

#[macro_use]
Expand All @@ -111,7 +131,8 @@ lazy_static! {
static ref MONITORING_API_URL: String = "https://monitoringapi.solaredge.com/".to_string();
}

const URL_TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S";
const URL_DATE_TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S";
const URL_DATE_FORMAT: &str = "%Y-%m-%d";

/// Struct for accessing SolarEdge's monitoring server for a given site and api key.
///
Expand All @@ -124,6 +145,14 @@ pub struct SolaredgeCredentials {

impl SolaredgeCredentials {
/// Create a Solaredge destination for the requests from the given site id and api_key.
///
/// # Arguments
///
/// * `site_id` - ID used by SolarEdge to identify your site.
/// * `api_key` - API token used SolarEdge to authenticate user is allowed to access site data.
///
/// # Returns
/// A credentials struct to be used in subsequent request sends.
#[must_use]
pub fn new(site_id: &str, api_key: &str) -> Self {
let site_id = site_id.to_string();
Expand All @@ -133,6 +162,7 @@ impl SolaredgeCredentials {
}

/// See the site ID being used in the credentials.
/// Used by the integration test framework.
#[must_use]
pub fn site_id(&self) -> &str {
&self.site_id
Expand All @@ -143,7 +173,7 @@ impl SolaredgeCredentials {
/// and getting the response is the same for all requests.
pub trait SendReq<Resp> {
#[doc(hidden)]
fn build_url(&self, solaredge: &SolaredgeCredentials) -> String;
fn build_url(&self, site_id: &str, api_key: &str) -> String;

/// Send the request to Solaredge and return the response.
///
Expand All @@ -160,13 +190,27 @@ pub trait SendReq<Resp> {
where
for<'de> Resp: Deserialize<'de>,
{
let url = self.build_url(solaredge);
let url = self.build_url(&solaredge.site_id, &solaredge.api_key);

let res = REQWEST_CLIENT.get(url).send()?;

if res.status().is_success() {
let parsed = res.json::<Resp>()?;

let res = REQWEST_CLIENT.get(&url).send()?;
Ok(parsed)
} else {
let reason = match res.status().canonical_reason() {
Some(r) => r.to_string(),
None => res.status().as_str().to_string(),
};

let parsed = res.json::<Resp>()?;
let text = match res.text() {
Ok(t) => t,
Err(_) => "".to_string(),
};

Ok(parsed)
Err(Error::new(Kind::HttpErrorStatus(reason, text)))
}
}
}

Expand Down
62 changes: 62 additions & 0 deletions src/site_data_period.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//! Module for querying the energy production start and end dates of the site.
use crate::{SendReq, MONITORING_API_URL};
use serde::Deserialize;

/// site_data_period request
#[derive(Clone, Debug, PartialEq)]
pub struct Req;

/// site_data_period response
#[derive(Clone, Deserialize, Debug, Default, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Resp {
/// Period of time site has been producing.
pub data_period: SiteDataPeriod,
}

/// Period of time site has been producing.
#[derive(Clone, Deserialize, Debug, Default, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SiteDataPeriod {
/// Start date of energy production.
pub start_date: Option<String>,
/// End date of energy production.
pub end_date: Option<String>,
}

impl Req {
/// Create a site_data_period request message that can be sent to SolarEdge.
#[must_use]
pub fn new() -> Self {
Req {}
}
}

impl SendReq<Resp> for Req {
fn build_url(&self, site_id: &str, api_key: &str) -> String {
format!(
"{}site/{}/dataPeriod?{}",
*MONITORING_API_URL, site_id, api_key,
)
}
}

impl Default for Req {
fn default() -> Self {
Self::new()
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::is_normal;

#[test]
fn normal_types_unit_test() {
is_normal::<Req>();
is_normal::<Resp>();
is_normal::<SiteDataPeriod>();
}
}
Loading

0 comments on commit 616b202

Please sign in to comment.