ambient_weather_progenitor/
lib.rs

1pub use progenitor_client::{ByteStream, Error, ResponseValue};
2#[allow(unused_imports)]
3use progenitor_client::{encode_path, RequestBuilderExt};
4#[allow(unused_imports)]
5use reqwest::header::{HeaderMap, HeaderValue};
6/// Types used as operation parameters and responses.
7#[allow(clippy::all)]
8pub mod types {
9    use serde::{Deserialize, Serialize};
10    #[allow(unused_imports)]
11    use std::convert::TryFrom;
12    /// Error types.
13    pub mod error {
14        /// Error from a TryFrom or FromStr implementation.
15        pub struct ConversionError(std::borrow::Cow<'static, str>);
16        impl std::error::Error for ConversionError {}
17        impl std::fmt::Display for ConversionError {
18            fn fmt(
19                &self,
20                f: &mut std::fmt::Formatter<'_>,
21            ) -> Result<(), std::fmt::Error> {
22                std::fmt::Display::fmt(&self.0, f)
23            }
24        }
25        impl std::fmt::Debug for ConversionError {
26            fn fmt(
27                &self,
28                f: &mut std::fmt::Formatter<'_>,
29            ) -> Result<(), std::fmt::Error> {
30                std::fmt::Debug::fmt(&self.0, f)
31            }
32        }
33        impl From<&'static str> for ConversionError {
34            fn from(value: &'static str) -> Self {
35                Self(value.into())
36            }
37        }
38        impl From<String> for ConversionError {
39            fn from(value: String) -> Self {
40                Self(value.into())
41            }
42        }
43    }
44    ///ListUsersDevicesResponseItem
45    ///
46    /// <details><summary>JSON schema</summary>
47    ///
48    /// ```json
49    ///{
50    ///  "type": "object",
51    ///  "properties": {
52    ///    "info": {
53    ///      "type": "object",
54    ///      "properties": {
55    ///        "location": {
56    ///          "type": "string"
57    ///        },
58    ///        "name": {
59    ///          "type": "string"
60    ///        }
61    ///      }
62    ///    },
63    ///    "lastData": {
64    ///      "type": "object",
65    ///      "properties": {
66    ///        "baromabsin": {
67    ///          "type": "number"
68    ///        },
69    ///        "baromrelin": {
70    ///          "type": "number"
71    ///        },
72    ///        "dailyrainin": {
73    ///          "type": "number"
74    ///        },
75    ///        "date": {
76    ///          "type": "string",
77    ///          "format": "date-time"
78    ///        },
79    ///        "dateutc": {
80    ///          "type": "number"
81    ///        },
82    ///        "dewPoint": {
83    ///          "type": "number"
84    ///        },
85    ///        "feelsLike": {
86    ///          "type": "number"
87    ///        },
88    ///        "hourlyrainin": {
89    ///          "type": "number"
90    ///        },
91    ///        "humidity": {
92    ///          "type": "number"
93    ///        },
94    ///        "humidityin": {
95    ///          "type": "number"
96    ///        },
97    ///        "maxdailygust": {
98    ///          "type": "number"
99    ///        },
100    ///        "monthlyrainin": {
101    ///          "type": "number"
102    ///        },
103    ///        "tempf": {
104    ///          "type": "number"
105    ///        },
106    ///        "tempinf": {
107    ///          "type": "number"
108    ///        },
109    ///        "winddir": {
110    ///          "type": "number"
111    ///        },
112    ///        "winddir_avg10m": {
113    ///          "type": "number"
114    ///        },
115    ///        "winddir_avg2m": {
116    ///          "type": "number"
117    ///        },
118    ///        "windgustdir": {
119    ///          "type": "number"
120    ///        },
121    ///        "windgustmph": {
122    ///          "type": "number"
123    ///        },
124    ///        "windspdmph_avg10m": {
125    ///          "type": "number"
126    ///        },
127    ///        "windspdmph_avg2m": {
128    ///          "type": "number"
129    ///        },
130    ///        "windspeedmph": {
131    ///          "type": "number"
132    ///        },
133    ///        "yearlyrainin": {
134    ///          "type": "number"
135    ///        }
136    ///      }
137    ///    },
138    ///    "macAddress": {
139    ///      "type": "string"
140    ///    }
141    ///  }
142    ///}
143    /// ```
144    /// </details>
145    #[derive(Clone, Debug, Deserialize, Serialize)]
146    pub struct ListUsersDevicesResponseItem {
147        #[serde(default, skip_serializing_if = "Option::is_none")]
148        pub info: Option<ListUsersDevicesResponseItemInfo>,
149        #[serde(rename = "lastData", default, skip_serializing_if = "Option::is_none")]
150        pub last_data: Option<ListUsersDevicesResponseItemLastData>,
151        #[serde(rename = "macAddress", default, skip_serializing_if = "Option::is_none")]
152        pub mac_address: Option<String>,
153    }
154    impl From<&ListUsersDevicesResponseItem> for ListUsersDevicesResponseItem {
155        fn from(value: &ListUsersDevicesResponseItem) -> Self {
156            value.clone()
157        }
158    }
159    ///ListUsersDevicesResponseItemInfo
160    ///
161    /// <details><summary>JSON schema</summary>
162    ///
163    /// ```json
164    ///{
165    ///  "type": "object",
166    ///  "properties": {
167    ///    "location": {
168    ///      "type": "string"
169    ///    },
170    ///    "name": {
171    ///      "type": "string"
172    ///    }
173    ///  }
174    ///}
175    /// ```
176    /// </details>
177    #[derive(Clone, Debug, Deserialize, Serialize)]
178    pub struct ListUsersDevicesResponseItemInfo {
179        #[serde(default, skip_serializing_if = "Option::is_none")]
180        pub location: Option<String>,
181        #[serde(default, skip_serializing_if = "Option::is_none")]
182        pub name: Option<String>,
183    }
184    impl From<&ListUsersDevicesResponseItemInfo> for ListUsersDevicesResponseItemInfo {
185        fn from(value: &ListUsersDevicesResponseItemInfo) -> Self {
186            value.clone()
187        }
188    }
189    ///ListUsersDevicesResponseItemLastData
190    ///
191    /// <details><summary>JSON schema</summary>
192    ///
193    /// ```json
194    ///{
195    ///  "type": "object",
196    ///  "properties": {
197    ///    "baromabsin": {
198    ///      "type": "number"
199    ///    },
200    ///    "baromrelin": {
201    ///      "type": "number"
202    ///    },
203    ///    "dailyrainin": {
204    ///      "type": "number"
205    ///    },
206    ///    "date": {
207    ///      "type": "string",
208    ///      "format": "date-time"
209    ///    },
210    ///    "dateutc": {
211    ///      "type": "number"
212    ///    },
213    ///    "dewPoint": {
214    ///      "type": "number"
215    ///    },
216    ///    "feelsLike": {
217    ///      "type": "number"
218    ///    },
219    ///    "hourlyrainin": {
220    ///      "type": "number"
221    ///    },
222    ///    "humidity": {
223    ///      "type": "number"
224    ///    },
225    ///    "humidityin": {
226    ///      "type": "number"
227    ///    },
228    ///    "maxdailygust": {
229    ///      "type": "number"
230    ///    },
231    ///    "monthlyrainin": {
232    ///      "type": "number"
233    ///    },
234    ///    "tempf": {
235    ///      "type": "number"
236    ///    },
237    ///    "tempinf": {
238    ///      "type": "number"
239    ///    },
240    ///    "winddir": {
241    ///      "type": "number"
242    ///    },
243    ///    "winddir_avg10m": {
244    ///      "type": "number"
245    ///    },
246    ///    "winddir_avg2m": {
247    ///      "type": "number"
248    ///    },
249    ///    "windgustdir": {
250    ///      "type": "number"
251    ///    },
252    ///    "windgustmph": {
253    ///      "type": "number"
254    ///    },
255    ///    "windspdmph_avg10m": {
256    ///      "type": "number"
257    ///    },
258    ///    "windspdmph_avg2m": {
259    ///      "type": "number"
260    ///    },
261    ///    "windspeedmph": {
262    ///      "type": "number"
263    ///    },
264    ///    "yearlyrainin": {
265    ///      "type": "number"
266    ///    }
267    ///  }
268    ///}
269    /// ```
270    /// </details>
271    #[derive(Clone, Debug, Deserialize, Serialize)]
272    pub struct ListUsersDevicesResponseItemLastData {
273        #[serde(default, skip_serializing_if = "Option::is_none")]
274        pub baromabsin: Option<f64>,
275        #[serde(default, skip_serializing_if = "Option::is_none")]
276        pub baromrelin: Option<f64>,
277        #[serde(default, skip_serializing_if = "Option::is_none")]
278        pub dailyrainin: Option<f64>,
279        #[serde(default, skip_serializing_if = "Option::is_none")]
280        pub date: Option<chrono::DateTime<chrono::offset::Utc>>,
281        #[serde(default, skip_serializing_if = "Option::is_none")]
282        pub dateutc: Option<f64>,
283        #[serde(rename = "dewPoint", default, skip_serializing_if = "Option::is_none")]
284        pub dew_point: Option<f64>,
285        #[serde(rename = "feelsLike", default, skip_serializing_if = "Option::is_none")]
286        pub feels_like: Option<f64>,
287        #[serde(default, skip_serializing_if = "Option::is_none")]
288        pub hourlyrainin: Option<f64>,
289        #[serde(default, skip_serializing_if = "Option::is_none")]
290        pub humidity: Option<f64>,
291        #[serde(default, skip_serializing_if = "Option::is_none")]
292        pub humidityin: Option<f64>,
293        #[serde(default, skip_serializing_if = "Option::is_none")]
294        pub maxdailygust: Option<f64>,
295        #[serde(default, skip_serializing_if = "Option::is_none")]
296        pub monthlyrainin: Option<f64>,
297        #[serde(default, skip_serializing_if = "Option::is_none")]
298        pub tempf: Option<f64>,
299        #[serde(default, skip_serializing_if = "Option::is_none")]
300        pub tempinf: Option<f64>,
301        #[serde(default, skip_serializing_if = "Option::is_none")]
302        pub winddir: Option<f64>,
303        #[serde(default, skip_serializing_if = "Option::is_none")]
304        pub winddir_avg10m: Option<f64>,
305        #[serde(default, skip_serializing_if = "Option::is_none")]
306        pub winddir_avg2m: Option<f64>,
307        #[serde(default, skip_serializing_if = "Option::is_none")]
308        pub windgustdir: Option<f64>,
309        #[serde(default, skip_serializing_if = "Option::is_none")]
310        pub windgustmph: Option<f64>,
311        #[serde(default, skip_serializing_if = "Option::is_none")]
312        pub windspdmph_avg10m: Option<f64>,
313        #[serde(default, skip_serializing_if = "Option::is_none")]
314        pub windspdmph_avg2m: Option<f64>,
315        #[serde(default, skip_serializing_if = "Option::is_none")]
316        pub windspeedmph: Option<f64>,
317        #[serde(default, skip_serializing_if = "Option::is_none")]
318        pub yearlyrainin: Option<f64>,
319    }
320    impl From<&ListUsersDevicesResponseItemLastData>
321    for ListUsersDevicesResponseItemLastData {
322        fn from(value: &ListUsersDevicesResponseItemLastData) -> Self {
323            value.clone()
324        }
325    }
326    ///QueryDeviceDataResponseItem
327    ///
328    /// <details><summary>JSON schema</summary>
329    ///
330    /// ```json
331    ///{
332    ///  "type": "object",
333    ///  "properties": {
334    ///    "baromabsin": {
335    ///      "type": "number"
336    ///    },
337    ///    "baromrelin": {
338    ///      "type": "number"
339    ///    },
340    ///    "dailyrainin": {
341    ///      "type": "number"
342    ///    },
343    ///    "date": {
344    ///      "type": "string",
345    ///      "format": "date-time"
346    ///    },
347    ///    "dateutc": {
348    ///      "type": "number"
349    ///    },
350    ///    "dewPoint": {
351    ///      "type": "number"
352    ///    },
353    ///    "feelsLike": {
354    ///      "type": "number"
355    ///    },
356    ///    "hourlyrainin": {
357    ///      "type": "number"
358    ///    },
359    ///    "humidity": {
360    ///      "type": "number"
361    ///    },
362    ///    "humidityin": {
363    ///      "type": "number"
364    ///    },
365    ///    "maxdailygust": {
366    ///      "type": "number"
367    ///    },
368    ///    "monthlyrainin": {
369    ///      "type": "number"
370    ///    },
371    ///    "tempf": {
372    ///      "type": "number"
373    ///    },
374    ///    "tempinf": {
375    ///      "type": "number"
376    ///    },
377    ///    "winddir": {
378    ///      "type": "number"
379    ///    },
380    ///    "winddir_avg10m": {
381    ///      "type": "number"
382    ///    },
383    ///    "winddir_avg2m": {
384    ///      "type": "number"
385    ///    },
386    ///    "windgustdir": {
387    ///      "type": "number"
388    ///    },
389    ///    "windgustmph": {
390    ///      "type": "number"
391    ///    },
392    ///    "windspdmph_avg10m": {
393    ///      "type": "number"
394    ///    },
395    ///    "windspdmph_avg2m": {
396    ///      "type": "number"
397    ///    },
398    ///    "windspeedmph": {
399    ///      "type": "number"
400    ///    },
401    ///    "yearlyrainin": {
402    ///      "type": "number"
403    ///    }
404    ///  }
405    ///}
406    /// ```
407    /// </details>
408    #[derive(Clone, Debug, Deserialize, Serialize)]
409    pub struct QueryDeviceDataResponseItem {
410        #[serde(default, skip_serializing_if = "Option::is_none")]
411        pub baromabsin: Option<f64>,
412        #[serde(default, skip_serializing_if = "Option::is_none")]
413        pub baromrelin: Option<f64>,
414        #[serde(default, skip_serializing_if = "Option::is_none")]
415        pub dailyrainin: Option<f64>,
416        #[serde(default, skip_serializing_if = "Option::is_none")]
417        pub date: Option<chrono::DateTime<chrono::offset::Utc>>,
418        #[serde(default, skip_serializing_if = "Option::is_none")]
419        pub dateutc: Option<f64>,
420        #[serde(rename = "dewPoint", default, skip_serializing_if = "Option::is_none")]
421        pub dew_point: Option<f64>,
422        #[serde(rename = "feelsLike", default, skip_serializing_if = "Option::is_none")]
423        pub feels_like: Option<f64>,
424        #[serde(default, skip_serializing_if = "Option::is_none")]
425        pub hourlyrainin: Option<f64>,
426        #[serde(default, skip_serializing_if = "Option::is_none")]
427        pub humidity: Option<f64>,
428        #[serde(default, skip_serializing_if = "Option::is_none")]
429        pub humidityin: Option<f64>,
430        #[serde(default, skip_serializing_if = "Option::is_none")]
431        pub maxdailygust: Option<f64>,
432        #[serde(default, skip_serializing_if = "Option::is_none")]
433        pub monthlyrainin: Option<f64>,
434        #[serde(default, skip_serializing_if = "Option::is_none")]
435        pub tempf: Option<f64>,
436        #[serde(default, skip_serializing_if = "Option::is_none")]
437        pub tempinf: Option<f64>,
438        #[serde(default, skip_serializing_if = "Option::is_none")]
439        pub winddir: Option<f64>,
440        #[serde(default, skip_serializing_if = "Option::is_none")]
441        pub winddir_avg10m: Option<f64>,
442        #[serde(default, skip_serializing_if = "Option::is_none")]
443        pub winddir_avg2m: Option<f64>,
444        #[serde(default, skip_serializing_if = "Option::is_none")]
445        pub windgustdir: Option<f64>,
446        #[serde(default, skip_serializing_if = "Option::is_none")]
447        pub windgustmph: Option<f64>,
448        #[serde(default, skip_serializing_if = "Option::is_none")]
449        pub windspdmph_avg10m: Option<f64>,
450        #[serde(default, skip_serializing_if = "Option::is_none")]
451        pub windspdmph_avg2m: Option<f64>,
452        #[serde(default, skip_serializing_if = "Option::is_none")]
453        pub windspeedmph: Option<f64>,
454        #[serde(default, skip_serializing_if = "Option::is_none")]
455        pub yearlyrainin: Option<f64>,
456    }
457    impl From<&QueryDeviceDataResponseItem> for QueryDeviceDataResponseItem {
458        fn from(value: &QueryDeviceDataResponseItem) -> Self {
459            value.clone()
460        }
461    }
462}
463#[derive(Clone, Debug)]
464/**Client for Ambient Weather REST API
465
466Access an Ambient Weather user's weather station data programmatically using our REST API
467
468##### Authentication
469
470Two API Keys are required for all REST API requests:
471
472+ `applicationKey` - identifies the developer / application. To create an application key please login to your AmbientWeather.net account page (https://ambientweather.net/account)
473
474+ `apiKey` - grants access to past/present data for a given user's devices.  A typical consumer-facing application will initially ask the user to create an `apiKey` on their AmbientWeather.net account page (https://ambientweather.net/account) and paste it into the app.  Developers for personal or in-house apps will also need to create an apiKey on their own account page.
475
476##### Rate Limiting
477
478API requests are capped at 1 request/second for each user's apiKey and 3 requests/second per applicationKey.  When this limit is exceeded, the API will return a 429 response code. Please be kind to our servers :)
479
480##### Helper Libraries
481
482+ Node.js - https://github.com/owise1/ambient-weather-api
483
484+ PHP (Laravel) - https://github.com/Jafo232/ambient_api
485
486+ Rust - https://github.com/JoshuaKimsey/ambient-weather-api
487
488+ Go - https://github.com/lrosenman/ambient
489
490+ Python - https://github.com/avryhof/ambient_api
491
492+ Python (asyncio) - https://github.com/bachya/aioambient
493
494+ R - https://github.com/andrewflack/ambientweatheR
495
496+ Java - https://github.com/rsv-code/ambient-weather-java
497
498+ Swift - https://github.com/MikeManzo/SwiftyWeatherKit
499
500+ .NET 5 - https://github.com/ChaseDRedmon/Cirrus
501
502##### Other Resources
503
504+ API Wiki - https://github.com/ambient-weather/api-docs/wiki
505
506+ This documentation's repository - https://github.com/ambient-weather/api-docs
507
508Version: 1.0.0*/
509pub struct Client {
510    pub(crate) baseurl: String,
511    pub(crate) client: reqwest::Client,
512}
513impl Client {
514    /// Create a new client.
515    ///
516    /// `baseurl` is the base URL provided to the internal
517    /// `reqwest::Client`, and should include a scheme and hostname,
518    /// as well as port and a path stem if applicable.
519    pub fn new(baseurl: &str) -> Self {
520        #[cfg(not(target_arch = "wasm32"))]
521        let client = {
522            let dur = std::time::Duration::from_secs(15);
523            reqwest::ClientBuilder::new().connect_timeout(dur).timeout(dur)
524        };
525        #[cfg(target_arch = "wasm32")]
526        let client = reqwest::ClientBuilder::new();
527        Self::new_with_client(baseurl, client.build().unwrap())
528    }
529    /// Construct a new client with an existing `reqwest::Client`,
530    /// allowing more control over its configuration.
531    ///
532    /// `baseurl` is the base URL provided to the internal
533    /// `reqwest::Client`, and should include a scheme and hostname,
534    /// as well as port and a path stem if applicable.
535    pub fn new_with_client(baseurl: &str, client: reqwest::Client) -> Self {
536        Self {
537            baseurl: baseurl.to_string(),
538            client,
539        }
540    }
541    /// Get the base URL to which requests are made.
542    pub fn baseurl(&self) -> &String {
543        &self.baseurl
544    }
545    /// Get the internal `reqwest::Client` used to make requests.
546    pub fn client(&self) -> &reqwest::Client {
547        &self.client
548    }
549    /// Get the version of this API.
550    ///
551    /// This string is pulled directly from the source OpenAPI
552    /// document and may be in any format the API selects.
553    pub fn api_version(&self) -> &'static str {
554        "1.0.0"
555    }
556}
557#[allow(clippy::all)]
558impl Client {
559    /**List User's Devices
560
561Provides a list of the user's available devices along with each device's most recent data.
562
563Sends a `GET` request to `/v1/devices`
564
565Arguments:
566- `api_key`: API Key for user account
567- `application_key`: Application Key
568*/
569    pub async fn list_users_devices<'a>(
570        &'a self,
571        api_key: &'a str,
572        application_key: &'a str,
573    ) -> Result<ResponseValue<Vec<types::ListUsersDevicesResponseItem>>, Error<()>> {
574        let url = format!("{}/v1/devices", self.baseurl,);
575        let mut query = Vec::with_capacity(2usize);
576        query.push(("apiKey", api_key.to_string()));
577        query.push(("applicationKey", application_key.to_string()));
578        #[allow(unused_mut)]
579        let mut request = self
580            .client
581            .get(url)
582            .header(
583                reqwest::header::ACCEPT,
584                reqwest::header::HeaderValue::from_static("application/json"),
585            )
586            .query(&query)
587            .build()?;
588        let result = self.client.execute(request).await;
589        let response = result?;
590        match response.status().as_u16() {
591            200u16 => ResponseValue::from_response(response).await,
592            429u16 => Err(Error::ErrorResponse(ResponseValue::empty(response))),
593            _ => Err(Error::UnexpectedResponse(response)),
594        }
595    }
596    /**Query Device Data
597
598Fetch data for a given device. Data is stored in 5 or 30 minute increments. A list of all possible fields is here: https://github.com/ambient-weather/api-docs/wiki/Device-Data-Specs
599
600Sends a `GET` request to `/v1/devices/{macAddress}`
601
602Arguments:
603- `mac_address`: device Mac Address
604- `api_key`: API Key for user account
605- `application_key`: Application Key
606- `end_date`: The most recent datetime. Results descend from there. If left blank, the most recent results will be returned.  Date format should be in milliseconds since the epoch or string representations outlined here: https://momentjs.com/docs/#/parsing/string/. Note: datetimes are stored in UTC.
607- `limit`: The maximum number of results to return (max: 288)
608*/
609    pub async fn query_device_data<'a>(
610        &'a self,
611        mac_address: &'a str,
612        api_key: &'a str,
613        application_key: &'a str,
614        end_date: Option<&'a chrono::DateTime<chrono::offset::Utc>>,
615        limit: Option<f64>,
616    ) -> Result<ResponseValue<Vec<types::QueryDeviceDataResponseItem>>, Error<()>> {
617        let url = format!(
618            "{}/v1/devices/{}", self.baseurl, encode_path(& mac_address.to_string()),
619        );
620        let mut query = Vec::with_capacity(4usize);
621        query.push(("apiKey", api_key.to_string()));
622        query.push(("applicationKey", application_key.to_string()));
623        if let Some(v) = &end_date {
624            query.push(("endDate", v.to_string()));
625        }
626        if let Some(v) = &limit {
627            query.push(("limit", v.to_string()));
628        }
629        #[allow(unused_mut)]
630        let mut request = self
631            .client
632            .get(url)
633            .header(
634                reqwest::header::ACCEPT,
635                reqwest::header::HeaderValue::from_static("application/json"),
636            )
637            .query(&query)
638            .build()?;
639        let result = self.client.execute(request).await;
640        let response = result?;
641        match response.status().as_u16() {
642            200u16 => ResponseValue::from_response(response).await,
643            429u16 => Err(Error::ErrorResponse(ResponseValue::empty(response))),
644            _ => Err(Error::UnexpectedResponse(response)),
645        }
646    }
647}
648/// Items consumers will typically use such as the Client.
649pub mod prelude {
650    pub use super::Client;
651}