1use anyhow::Result;
2use iso8601_timestamp::Timestamp;
3use reqwest::Client;
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
9#[serde(rename_all = "camelCase")]
10pub struct SiteDetails {
11 pub active_from: Timestamp,
12 pub channels: Vec<SiteChannels>,
13 pub id: String,
14 pub network: String,
15 pub nmi: String,
16 pub status: String,
17}
18#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
20pub struct SiteChannels {
21 pub identifier: String,
22 pub tariff: String,
23 #[serde(rename = "type")]
25 pub tariff_type: String,
26}
27
28#[derive(Serialize, Deserialize, Debug, Clone)]
30#[serde(rename_all = "camelCase")]
31pub struct PriceData {
32 #[serde(rename = "type")]
34 pub interval_type: String,
35 pub date: Timestamp,
36 pub duration: u8,
37 pub start_time: Timestamp,
38 pub end_time: Timestamp,
39 pub nem_time: Timestamp,
40 pub per_kwh: f32,
41 pub renewables: f32,
42 pub spot_per_kwh: f32,
43 pub channel_type: String,
44 pub spike_status: String,
45 pub tariff_information: TariffInformation,
46 pub descriptor: String,
47 pub estimate: Option<bool>,
48}
49
50#[derive(Serialize, Deserialize, Debug, Clone)]
52#[serde(rename_all = "camelCase")]
53pub struct UsageData {
54 #[serde(rename = "type")]
55 pub price_type: String,
56 pub duration: u8,
57 pub date: Timestamp,
58 pub end_time: Timestamp,
59 pub quality: String,
60 pub kwh: f32,
61 pub nem_time: Timestamp,
62 pub per_kwh: f32,
63 pub channel_type: String,
64 pub channel_identifier: String,
65 pub cost: f32,
66 pub renewables: f32,
67 pub spot_per_kwh: f32,
68 pub start_time: Timestamp,
69 pub spike_status: String,
70 pub tariff_information: TariffInformation,
71 pub descriptor: String,
72}
73
74#[derive(Serialize, Deserialize, Debug, Clone)]
76pub struct TariffInformation {
77 pub period: String,
78}
79
80#[derive(Serialize, Deserialize, Debug, Clone)]
82#[serde(rename_all = "camelCase")]
83pub struct RenewablesData {
84 #[serde(rename = "type")]
85 pub price_type: String,
86 pub duration: u8,
87 pub date: Timestamp,
88 pub start_time: Timestamp,
89 pub end_time: Timestamp,
90 pub renewables: f32,
91 pub descriptor: String,
92}
93
94#[derive(Clone)]
96pub struct RestClient {
97 pub url: String,
98 pub auth_token: String,
99 pub client: reqwest::Client,
100}
101
102#[derive(Error, Debug)]
104pub enum Error {
105 #[error("HTTP Request failed: {0}")]
106 ReqwestError(#[from] reqwest::Error),
107
108 #[error("Serde failed to decode json: {0}")]
109 SerdeJsonError(#[from] serde_json::Error),
110
111 #[error("Received a non 200 status code of {status_code:?} with message body: {body:?} ")]
112 HttpNon200Status { status_code: String, body: String },
113}
114
115impl RestClient {
117 pub fn new_client(url: String, auth_token: String) -> Self {
118 Self {
119 url,
120 auth_token,
121 client: Client::new(),
122 }
123 }
124
125 pub async fn get_site_data(&mut self) -> Result<Vec<SiteDetails>, Error> {
127 let auth_token_header = format!("Bearer {}", &self.auth_token);
128
129 let response = self
130 .client
131 .get(&self.url)
132 .header("AUTHORIZATION", auth_token_header)
133 .header("CONTENT_TYPE", "application/json")
134 .header("ACCEPT", "application/json")
135 .send()
136 .await?;
137 match response.status() {
138 reqwest::StatusCode::OK => {
139 let response = response.json::<Vec<SiteDetails>>().await?;
140 Ok(response)
141 }
142 _ => Err(Error::HttpNon200Status {
143 status_code: (response.status().to_string()),
144 body: (response.text().await)?,
145 }),
146 }
147 }
148
149 pub async fn get_price_data(&mut self) -> Result<Vec<PriceData>> {
151 let auth_token_header = format!("Bearer {}", &self.auth_token);
152
153 let response = self
154 .client
155 .get(&self.url)
156 .header("AUTHORIZATION", auth_token_header)
157 .header("CONTENT_TYPE", "application/json")
158 .header("ACCEPT", "application/json")
159 .send()
160 .await?
161 .json::<Vec<PriceData>>()
162 .await?;
163
164 Ok(response)
165 }
166
167 pub async fn get_usage_data(&mut self) -> Result<Vec<UsageData>> {
169 let auth_token_header = format!("Bearer {}", &self.auth_token);
170
171 let response = self
172 .client
173 .get(&self.url)
174 .header("AUTHORIZATION", auth_token_header)
175 .header("CONTENT_TYPE", "application/json")
176 .header("ACCEPT", "application/json")
177 .send()
178 .await?
179 .json::<Vec<UsageData>>()
180 .await?;
181
182 Ok(response)
183 }
184
185 pub async fn get_renewables_data(&self) -> Result<Vec<RenewablesData>> {
187 let auth_token_header = format!("Bearer {}", &self.auth_token);
188
189 let response = self
190 .client
191 .get(&self.url)
192 .header("AUTHORIZATION", auth_token_header)
193 .header("CONTENT_TYPE", "application/json")
194 .header("ACCEPT", "application/json")
195 .send()
196 .await?
197 .json::<Vec<RenewablesData>>()
198 .await?;
199
200 Ok(response)
201 }
202}