pvoutput_client/client/
get.rs

1//! Read-only API endpoint methods.
2
3use const_format::formatcp;
4use jiff::civil::Date;
5use serde::Serialize;
6
7use crate::{
8	API_BASE_URL, Client, parser,
9	parser::parse_none,
10	types::{
11		error::NoEndpointSpecificError,
12		params::{
13			Aggregation, GetExtendedParams, GetInsolationParams, GetOutputParams, GetOutputParamsOuter, GetStatisticsParams,
14			GetStatusParams, GetStatusParamsOuter, GetSystemParams,
15		},
16		regions::Region,
17		response::{
18			AggregatedOutput, DailyStatus, ExtendedData, FavouriteSystem, FullSystem, History, Insolation, Ladder, Output,
19			Response, Statistics, Status, Supply, Team, TeamOutput,
20		},
21	},
22};
23
24impl Client {
25	/// Retrieves a single status for the specified system.
26	///
27	/// - For historic data (`h`), use [`Client::get_status_history`]
28	/// - For statistics (`stats`), use [`Client::get_status_daily`]
29	///
30	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-status-service)
31	pub async fn get_status(&self, params: GetStatusParams) -> crate::Result<Response<Status>, NoEndpointSpecificError> {
32		self
33			.get_single(
34				formatcp!("{API_BASE_URL}/getstatus.jsp"),
35				GetStatusParamsOuter::new(params, false, false),
36				parse_none,
37			)
38			.await
39	}
40
41	/// Retrieves historic statuses for the specified system.
42	///
43	/// - For a single measurement, use [`Client::get_status`]
44	/// - For statistics (`stats`), use [`Client::get_status_daily`]
45	///
46	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-status-service)
47	pub async fn get_status_history(
48		&self,
49		params: GetStatusParams,
50	) -> crate::Result<Response<Vec<History>>, NoEndpointSpecificError> {
51		self
52			.get_multiple(
53				formatcp!("{API_BASE_URL}/getstatus.jsp"),
54				GetStatusParamsOuter::new(params, true, false),
55				parse_none,
56			)
57			.await
58	}
59
60	/// Retrieves a daily stats summary for the specified system.
61	///
62	/// - For historic data (`h`), use [`Client::get_status_history`]
63	/// - For a single measurement, use [`Client::get_status`]
64	///
65	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-status-service)
66	pub async fn get_status_daily(
67		&self,
68		params: GetStatusParams,
69	) -> crate::Result<Response<DailyStatus>, NoEndpointSpecificError> {
70		let (rate_limit, response) = self
71			.get(
72				formatcp!("{API_BASE_URL}/getstatus.jsp"),
73				GetStatusParamsOuter::new(params, false, true),
74				parse_none,
75			)
76			.await?;
77
78		Ok(Response::new(parser::daily_status(&response)?, rate_limit))
79	}
80
81	/// Retrieves statistics for a system.
82	///
83	/// This endpoint has a rate limit of **twelve** requests per hour for free accounts, and **sixty** for accounts with
84	/// [donation status](https://pvoutput.org/help/donations.html).
85	///
86	/// This information is not exposed by the API -- the `rate_limit` on the `Response` struct will not reflect these
87	/// limits.
88	///
89	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-statistic-service)
90	pub async fn get_statistics(
91		&self,
92		params: GetStatisticsParams,
93	) -> crate::Result<Response<Statistics>, NoEndpointSpecificError> {
94		let (rate_limit, response) = self.get(formatcp!("{API_BASE_URL}/getstatistic.jsp"), &params, parse_none).await?;
95
96		Ok(Response::new(parser::statistics(&response, &params)?, rate_limit))
97	}
98
99	/// Retrieves system information.
100	///
101	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-system-service)
102	pub async fn get_system(
103		&self,
104		params: GetSystemParams,
105	) -> crate::Result<Response<FullSystem>, NoEndpointSpecificError> {
106		let (rate_limit, response) = self.get(formatcp!("{API_BASE_URL}/getsystem.jsp"), &params, parse_none).await?;
107
108		Ok(Response::new(parser::system(&response, &params)?, rate_limit))
109	}
110
111	/// Retrieves a system's ladder ranking.
112	///
113	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-ladder-service)
114	///
115	/// # Parameters
116	/// - `system`: System ID to retrieve status for.
117	///   If unset, the [`Client`]'s authenticated system is used.
118	///   Requires [donation status](https://pvoutput.org/help/donations.html).
119	pub async fn get_ladder(&self, system: Option<u32>) -> crate::Result<Response<Ladder>, NoEndpointSpecificError> {
120		self.get_single(formatcp!("{API_BASE_URL}/getladder.jsp"), &[("sid1", system)], parse_none).await
121	}
122
123	/// Retrieves daily outputs.
124	///
125	/// - For aggregated outputs (`a`), use [`Client::get_aggregate_outputs`]
126	/// - For team outputs (`tid`), use [`Client::get_team_outputs`]
127	///
128	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-output-service)
129	pub async fn get_outputs(
130		&self,
131		params: GetOutputParams,
132	) -> crate::Result<Response<Vec<Output>>, NoEndpointSpecificError> {
133		let params = GetOutputParamsOuter {
134			params,
135			..Default::default()
136		};
137
138		let (rate_limit, response) = self.get(formatcp!("{API_BASE_URL}/getoutput.jsp"), &params, parse_none).await?;
139		Ok(Response::new(parser::outputs(&response, &params.params)?, rate_limit))
140	}
141
142	/// Retrieves monthly or yearly aggregated outputs.
143	///
144	/// - For daily outputs, use [`Client::get_outputs`]
145	/// - For team outputs (`tid`), use [`Client::get_team_outputs`]
146	///
147	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-output-service)
148	pub async fn get_aggregate_outputs(
149		&self,
150		aggregation: Aggregation,
151		params: GetOutputParams,
152	) -> crate::Result<Response<Vec<AggregatedOutput>>, NoEndpointSpecificError> {
153		let params = GetOutputParamsOuter {
154			params,
155			a: Some(aggregation),
156			..Default::default()
157		};
158
159		let (rate_limit, response) = self.get(formatcp!("{API_BASE_URL}/getoutput.jsp"), &params, parse_none).await?;
160		Ok(Response::new(parser::aggregate_outputs(&response, params.params.time_of_export)?, rate_limit))
161	}
162
163	/// Retrieves daily outputs for the given team.
164	///
165	/// - For daily outputs, use [`Client::get_outputs`]
166	/// - For aggregated outputs (`a`), use [`Client::get_aggregate_outputs`]
167	///
168	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-output-service)
169	pub async fn get_team_outputs(
170		&self,
171		team_id: u32,
172		params: GetOutputParams,
173	) -> crate::Result<Response<Vec<TeamOutput>>, NoEndpointSpecificError> {
174		self
175			.get_multiple(
176				formatcp!("{API_BASE_URL}/getoutput.jsp"),
177				GetOutputParamsOuter {
178					params,
179					tid: Some(team_id),
180					..Default::default()
181				},
182				parse_none,
183			)
184			.await
185	}
186
187	/// Retrieves daily extended output values for your system.
188	///
189	/// Requires [donation status](https://pvoutput.org/help/donations.html).
190	///
191	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-extended-service)
192	///
193	/// # Errors
194	/// Returns [`ClientError::NotFound`](crate::ClientError::NotFound) if your system has no extended data for the
195	/// specified date range.
196	pub async fn get_extended(
197		&self,
198		params: GetExtendedParams,
199	) -> crate::Result<Response<Vec<ExtendedData>>, NoEndpointSpecificError> {
200		self.get_multiple(formatcp!("{API_BASE_URL}/getextended.jsp"), &params, parse_none).await
201	}
202
203	/// Gets a system's favourite systems.
204	/// Limited to fifty systems.
205	///
206	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-favourite-service)
207	///
208	/// # Parameters
209	/// - `system`: System ID to retrieve favourites for.
210	///   If unset, the [`Client`]'s authenticated system is used.
211	///   Requires [donation status](https://pvoutput.org/help/donations.html).
212	pub async fn get_favourites(
213		&self,
214		system: Option<u32>,
215	) -> crate::Result<Response<Vec<FavouriteSystem>>, NoEndpointSpecificError> {
216		let (rate_limit, response) =
217			self.get(formatcp!("{API_BASE_URL}/getfavourite.jsp"), &[("sid1", system)], parse_none).await?;
218		Ok(Response::new(parser::favourites(&response)?, rate_limit))
219	}
220
221	/// Retrieves a list of missing output dates for your system.
222	///
223	/// A maximum of **fifty** missing dates will be returned in ascending order (i.e., oldest to most recent).
224	///
225	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-missing-service)
226	pub async fn get_missing(
227		&self,
228		from: Option<Date>,
229		to: Option<Date>,
230	) -> crate::Result<Response<Vec<Date>>, NoEndpointSpecificError> {
231		self
232			.get_single(
233				formatcp!("{API_BASE_URL}/getmissing.jsp"),
234				&[
235					("df", from.map(|d| d.strftime("%Y%m%d").to_string())),
236					("dt", to.map(|d| d.strftime("%Y%m%d").to_string())),
237				],
238				parse_none,
239			)
240			.await
241	}
242
243	/// Retrieves insolation data at five minute intervals.
244	///
245	/// Requires [donation status](https://pvoutput.org/help/donations.html).
246	///
247	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-insolation-service)
248	pub async fn get_insolation(
249		&self,
250		params: GetInsolationParams,
251	) -> crate::Result<Response<Vec<Insolation>>, NoEndpointSpecificError> {
252		self.get_multiple(formatcp!("{API_BASE_URL}/getinsolation.jsp"), &params, parse_none).await
253	}
254
255	/// Retrieves team data.
256	///
257	/// Only team owners may retrieve details of their own team.
258	/// [Donation-enabled](https://pvoutput.org/help/donations.html) accounts may query any team.
259	///
260	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-team-service)
261	pub async fn get_team(&self, team: u32) -> crate::Result<Response<Team>, NoEndpointSpecificError> {
262		// why is this a semicolon-delimited response??
263		let (rate_limit, response) =
264			self.get(formatcp!("{API_BASE_URL}/getteam.jsp"), &[("tid", team)], parse_none).await?;
265
266		Ok(Response::new(
267			Self::semicolon_reader(&response).deserialize().collect::<csv::Result<Vec<_>>>()?.remove(0),
268			rate_limit,
269		))
270	}
271
272	/// Retrieves aggregated live generation and consumption data.
273	///
274	/// # Parameters
275	/// - `region`: Region to retrieve data for.
276	///   If provided, the 24-hour supply and demand history for the region will be returned.
277	///   Requires [donation status](https://pvoutput.org/help/donations.html).
278	/// - `timezone`: Timezone to use in responses.
279	///   If unset, data will be returned in UTC.
280	///
281	/// [PVOutput docs](https://pvoutput.org/help/api_specification.html#get-supply-service)
282	pub async fn get_supply(
283		&self,
284		region: Option<Region>,
285		timezone: Option<String>,
286	) -> crate::Result<Response<Vec<Supply>>, NoEndpointSpecificError> {
287		#[derive(Serialize)]
288		struct Params {
289			r: Option<Region>,
290			tz: Option<String>,
291		}
292
293		let params = Params {
294			r: region,
295			tz: timezone,
296		};
297		self.get_multiple(formatcp!("{API_BASE_URL}/getsupply.jsp"), &params, parse_none).await
298	}
299}