franklin_wh/
lib.rs

1use reqwest::{self, Url};
2
3mod responses;
4
5const DEFAULT_URL_BASE: &'static str  = "https://energy.franklinwh.com";
6
7struct Api {
8    base: Url,
9}
10
11impl Default for Api {
12    fn default() -> Self {
13        Self::new(DEFAULT_URL_BASE)
14            .unwrap() // We know the DEFAULT_URL_BASE will always parse ok
15    }
16}
17
18impl Api {
19    pub fn new<'a>(base: &'a str) -> Result<Self, ()> {
20        let base = Url::parse(base).map_err(|_| ())?;
21        Ok(Api {
22            base,
23        })
24    }
25
26    pub fn charge_power_details(&self) -> Url {
27        self.base.join("hes-gateway/terminal/chargePowerDetails")
28            .unwrap() // We know this is a valid suffix
29    }
30
31    pub fn iot_user_runtime_datalog(&self) -> Url {
32        self.base.join("hes-gateway/terminal/selectIotUserRuntimeDataLog")
33            .unwrap() // We know this is a valid suffix
34    }
35}
36
37pub struct Client {
38    api: Api,
39    token: String,
40    client: reqwest::Client,
41    gateway: String,
42}
43
44impl Client {
45    pub fn new<'a>(token: &'a str, gateway: &'a str) -> Self {
46        Client {
47            api: Default::default(),
48            token: token.into(),
49            client: Default::default(),
50            gateway: gateway.into(),
51        }
52    }
53
54    /// Return the current state of charge from 0 to 100
55    pub async fn get_state_of_charge(&self) -> Result<f32, ()> {
56        let response = self.get(&self.api.charge_power_details())
57            .await.map_err(|_| ())?
58            .json::<responses::ChargePowerDetails>()
59            .await.map_err(|_| ())?;
60
61        return response.inner().map(|x| x.batterySoc);
62    }
63
64    pub async fn get_iot_user_runtime_datalog(&self) -> Result<(), ()> {
65        let response = self.get(&self.api.iot_user_runtime_datalog())
66            .await.map_err(|_| ())?
67            .json::<responses::IoTUserRuntimeDataLog>()
68            .await.map_err(|_| ())?;
69
70        return Ok(())
71    }
72
73
74    /// Make a GET request with authentication etc handled for you.
75    async fn get(&self, url: &Url) -> Result<reqwest::Response, reqwest::Error> {
76        self.client
77            .get(url.clone())
78            .query(&[("gatewayId", &self.gateway)])
79            .header("loginToken", format!("APP_ACCOUNT:{}", self.token))
80            .send().await
81    }
82}
83
84