Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrk - Mostly added a bunch of messages #11

Merged
merged 14 commits into from
May 23, 2022
Merged
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