homeassistant/
rest.rs

1use crate::errors;
2use crate::types;
3use serde::{Deserialize, Serialize};
4use std::convert::TryFrom;
5use std::sync::{Arc, RwLock, Weak};
6
7#[derive(Debug)]
8pub struct Rest {
9    ha_client: Arc<RwLock<crate::HomeAssistantAPI>>,
10}
11
12impl Rest {
13    pub async fn check(self) -> Result<String, errors::Error> {
14        let mut read_lock = self.ha_client.read().unwrap();
15        if read_lock.token.need_refresh() {
16            drop(read_lock);
17            let mut write_lock = self.ha_client.write().unwrap();
18            write_lock.refresh_oauth_token().await?;
19            read_lock = self.ha_client.read().unwrap();
20        }
21
22        let endpoint = format!("{}/api/config", read_lock.instance_url);
23        let request = reqwest::Client::new()
24            .get(endpoint.as_str())
25            .header(
26                "Authorization",
27                format!("Bearer {}", read_lock.token.as_string()?),
28            )
29            .header("content-type", "application/json");
30
31        drop(read_lock);
32        let response = request.send().await?;
33
34        #[derive(Serialize, Deserialize, Debug)]
35        struct Response {
36            message: String,
37        }
38
39        let resp_json: Response = response.json().await?;
40
41        Ok(resp_json.message)
42
43        //Err(errors::Error::HaApi(String::from("Not Implemented")))
44    }
45
46    pub async fn config(self) -> Result<types::Configuration, errors::Error> {
47        let mut read_lock = self.ha_client.read().unwrap();
48        if read_lock.token.need_refresh() {
49            drop(read_lock);
50            let mut write_lock = self.ha_client.write().unwrap();
51            write_lock.refresh_oauth_token().await?;
52            read_lock = self.ha_client.read().unwrap();
53        }
54
55        let endpoint = format!("{}/api/config", read_lock.instance_url);
56        let request = reqwest::Client::new()
57            .get(endpoint.as_str())
58            .header(
59                "Authorization",
60                format!("Bearer {}", read_lock.token.as_string()?),
61            )
62            .header("content-type", "application/json");
63
64        drop(read_lock);
65        let response = request.send().await?;
66
67        let resp_json: types::Configuration = response.json().await?;
68
69        Ok(resp_json)
70    }
71
72    pub async fn discovery_info(self) -> Result<types::DiscoveryInfo, errors::Error> {
73        let mut read_lock = self.ha_client.read().unwrap();
74        if read_lock.token.need_refresh() {
75            drop(read_lock);
76            let mut write_lock = self.ha_client.write().unwrap();
77            write_lock.refresh_oauth_token().await?;
78            read_lock = self.ha_client.read().unwrap();
79        }
80
81        let endpoint = format!("{}/api/discovery_info", read_lock.instance_url);
82        let request = reqwest::Client::new()
83            .get(endpoint.as_str())
84            .header(
85                "Authorization",
86                format!("Bearer {}", read_lock.token.as_string()?),
87            )
88            .header("content-type", "application/json");
89
90        drop(read_lock);
91        let response = request.send().await?;
92
93        let resp_json: types::DiscoveryInfo = response.json().await?;
94
95        Ok(resp_json)
96    }
97
98    pub async fn events(self) -> Result<Vec<types::EventObject>, errors::Error> {
99        let mut read_lock = self.ha_client.read().unwrap();
100        if read_lock.token.need_refresh() {
101            drop(read_lock);
102            let mut write_lock = self.ha_client.write().unwrap();
103            write_lock.refresh_oauth_token().await?;
104            read_lock = self.ha_client.read().unwrap();
105        }
106
107        let endpoint = format!("{}/api/events", read_lock.instance_url);
108        let request = reqwest::Client::new()
109            .get(endpoint.as_str())
110            .header(
111                "Authorization",
112                format!("Bearer {}", read_lock.token.as_string()?),
113            )
114            .header("content-type", "application/json");
115
116        drop(read_lock);
117        let response = request.send().await?;
118
119        let resp_json: Vec<types::EventObject> = response.json().await?;
120
121        Ok(resp_json)
122    }
123
124    pub async fn services(self) -> Result<Vec<types::ServiceObject>, errors::Error> {
125        let mut read_lock = self.ha_client.read().unwrap();
126        if read_lock.token.need_refresh() {
127            drop(read_lock);
128            let mut write_lock = self.ha_client.write().unwrap();
129            write_lock.refresh_oauth_token().await?;
130            read_lock = self.ha_client.read().unwrap();
131        }
132
133        let endpoint = format!("{}/api/services", read_lock.instance_url);
134        let request = reqwest::Client::new()
135            .get(endpoint.as_str())
136            .header(
137                "Authorization",
138                format!("Bearer {}", read_lock.token.as_string()?),
139            )
140            .header("content-type", "application/json");
141
142        drop(read_lock);
143        let response = request.send().await?;
144
145        let resp_json: Vec<types::ServiceObject> = response.json().await?;
146
147        Ok(resp_json)
148    }
149
150    pub async fn history_period(
151        self,
152        timestamp: Option<chrono::DateTime<chrono::Utc>>,
153        filter_entity_id: Option<String>,
154        end_time: Option<chrono::DateTime<chrono::Utc>>,
155        significant_changes_only: Option<bool>,
156    ) -> Result<Vec<types::StateObject>, errors::Error> {
157        let mut read_lock = self.ha_client.read().unwrap();
158        if read_lock.token.need_refresh() {
159            drop(read_lock);
160            let mut write_lock = self.ha_client.write().unwrap();
161            write_lock.refresh_oauth_token().await?;
162            read_lock = self.ha_client.read().unwrap();
163        }
164
165        let mut endpoint = format!("{}/api/history/period", read_lock.instance_url);
166
167        if let Some(timestamp) = timestamp {
168            let formatted_timestamp = timestamp.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
169            endpoint = endpoint + &formatted_timestamp;
170        }
171
172        let mut request = reqwest::Client::new()
173            .get(endpoint.as_str())
174            .header(
175                "Authorization",
176                format!("Bearer {}", read_lock.token.as_string()?),
177            )
178            .header("content-type", "application/json");
179
180        drop(read_lock);
181
182        if let Some(filter_entity_id) = filter_entity_id {
183            request = request.query(&[("filter_entity_id", filter_entity_id)]);
184        }
185
186        if let Some(end_time) = end_time {
187            let formatted_timestamp = end_time.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
188            request = request.query(&[("end_time", formatted_timestamp)]);
189        }
190
191        if significant_changes_only.is_some() {
192            request = request.query(&[("significant_changes_only")]);
193        }
194
195        let response = request.send().await?;
196
197        let resp_json: Vec<types::StateObject> = response.json().await?;
198
199        Ok(resp_json)
200    }
201
202    pub async fn history_period_minimal(
203        self,
204        timestamp: Option<chrono::DateTime<chrono::Utc>>,
205        filter_entity_id: Option<String>,
206        end_time: Option<chrono::DateTime<chrono::Utc>>,
207        significant_changes_only: Option<bool>,
208    ) -> Result<Vec<types::StateObject>, errors::Error> {
209        let mut read_lock = self.ha_client.read().unwrap();
210        if read_lock.token.need_refresh() {
211            drop(read_lock);
212            let mut write_lock = self.ha_client.write().unwrap();
213            write_lock.refresh_oauth_token().await?;
214            read_lock = self.ha_client.read().unwrap();
215        }
216
217        let mut endpoint = format!("{}/api/history/period", read_lock.instance_url);
218
219        if let Some(timestamp) = timestamp {
220            let formatted_timestamp = timestamp.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
221            endpoint = endpoint + &formatted_timestamp;
222        }
223
224        let mut request = reqwest::Client::new()
225            .get(endpoint.as_str())
226            .header(
227                "Authorization",
228                format!("Bearer {}", read_lock.token.as_string()?),
229            )
230            .header("content-type", "application/json");
231
232        drop(read_lock);
233
234        if let Some(filter_entity_id) = filter_entity_id {
235            request = request.query(&[("filter_entity_id", filter_entity_id)]);
236        }
237
238        if let Some(end_time) = end_time {
239            let formatted_timestamp = end_time.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
240            request = request.query(&[("end_time", formatted_timestamp)]);
241        }
242
243        if significant_changes_only.is_some() {
244            request = request.query(&[("significant_changes_only")]);
245        }
246
247        request = request.query(&[("minimal_response")]);
248
249        let response = request.send().await?;
250
251        let resp_json: Vec<types::StateObject> = response.json().await?;
252
253        Ok(resp_json)
254    }
255
256    pub async fn logbook(
257        self,
258        timestamp: Option<chrono::DateTime<chrono::Utc>>,
259        entity: String,
260        end_time: Option<chrono::DateTime<chrono::Utc>>,
261    ) -> Result<Vec<types::LogbookEntry>, errors::Error> {
262        let mut read_lock = self.ha_client.read().unwrap();
263        if read_lock.token.need_refresh() {
264            drop(read_lock);
265            let mut write_lock = self.ha_client.write().unwrap();
266            write_lock.refresh_oauth_token().await?;
267            read_lock = self.ha_client.read().unwrap();
268        }
269
270        let mut endpoint = format!("{}/api/logbook", read_lock.instance_url);
271
272        if let Some(timestamp) = timestamp {
273            let formatted_timestamp = timestamp.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
274            endpoint = endpoint + &formatted_timestamp;
275        }
276
277        let mut request = reqwest::Client::new()
278            .get(endpoint.as_str())
279            .header(
280                "Authorization",
281                format!("Bearer {}", read_lock.token.as_string()?),
282            )
283            .header("content-type", "application/json");
284
285        drop(read_lock);
286
287        request = request.query(&[("entity", entity)]);
288
289        if let Some(end_time) = end_time {
290            let formatted_timestamp = end_time.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
291            request = request.query(&[("end_time", formatted_timestamp)]);
292        }
293
294        let response = request.send().await?;
295
296        let resp_json: Vec<types::LogbookEntry> = response.json().await?;
297
298        Ok(resp_json)
299    }
300
301    pub async fn states(self) -> Result<Vec<types::StateObject>, errors::Error> {
302        let mut read_lock = self.ha_client.read().unwrap();
303        if read_lock.token.need_refresh() {
304            drop(read_lock);
305            let mut write_lock = self.ha_client.write().unwrap();
306            write_lock.refresh_oauth_token().await?;
307            read_lock = self.ha_client.read().unwrap();
308        }
309
310        let endpoint = format!("{}/api/states", read_lock.instance_url);
311        let request = reqwest::Client::new()
312            .get(endpoint.as_str())
313            .header(
314                "Authorization",
315                format!("Bearer {}", read_lock.token.as_string()?),
316            )
317            .header("content-type", "application/json");
318
319        drop(read_lock);
320        let response = request.send().await?;
321
322        let resp_json: Vec<types::StateObject> = response.json().await?;
323
324        Ok(resp_json)
325    }
326
327    pub async fn state_of(
328        self,
329        entity_id: String,
330    ) -> Result<Vec<types::StateObject>, errors::Error> {
331        let mut read_lock = self.ha_client.read().unwrap();
332        if read_lock.token.need_refresh() {
333            drop(read_lock);
334            let mut write_lock = self.ha_client.write().unwrap();
335            write_lock.refresh_oauth_token().await?;
336            read_lock = self.ha_client.read().unwrap();
337        }
338
339        let endpoint = format!("{}/api/states/{}", read_lock.instance_url, entity_id);
340        let request = reqwest::Client::new()
341            .get(endpoint.as_str())
342            .header(
343                "Authorization",
344                format!("Bearer {}", read_lock.token.as_string()?),
345            )
346            .header("content-type", "application/json");
347
348        drop(read_lock);
349        let response = request.send().await?;
350        let resp_json: Vec<types::StateObject> = response.json().await?;
351
352        Ok(resp_json)
353    }
354
355    pub async fn error_log(self) -> Result<String, errors::Error> {
356        let mut read_lock = self.ha_client.read().unwrap();
357        if read_lock.token.need_refresh() {
358            drop(read_lock);
359            let mut write_lock = self.ha_client.write().unwrap();
360            write_lock.refresh_oauth_token().await?;
361            read_lock = self.ha_client.read().unwrap();
362        }
363
364        let endpoint = format!("{}/api/error_log", read_lock.instance_url);
365        let request = reqwest::Client::new()
366            .get(endpoint.as_str())
367            .header(
368                "Authorization",
369                format!("Bearer {}", read_lock.token.as_string()?),
370            )
371            .header("content-type", "application/json");
372
373        drop(read_lock);
374        let response = request.send().await?;
375
376        let resp: String = response.text().await?;
377
378        Ok(resp)
379    }
380
381    pub async fn camera_proxy(self, camera_entity_id: String) -> Result<(), errors::Error> {
382        let mut read_lock = self.ha_client.read().unwrap();
383        if read_lock.token.need_refresh() {
384            drop(read_lock);
385            let mut write_lock = self.ha_client.write().unwrap();
386            write_lock.refresh_oauth_token().await?;
387            read_lock = self.ha_client.read().unwrap();
388        }
389
390        let endpoint = format!(
391            "{}/api/camera_proxy/{}",
392            read_lock.instance_url, camera_entity_id
393        );
394        let request = reqwest::Client::new()
395            .get(endpoint.as_str())
396            .header(
397                "Authorization",
398                format!("Bearer {}", read_lock.token.as_string()?),
399            )
400            .header("content-type", "application/json");
401
402        drop(read_lock);
403        let _response = request.send().await?;
404
405        Ok(())
406    }
407
408    pub async fn state_change(
409        self,
410        entity_id: String,
411        state_data: Option<impl serde::Serialize>,
412    ) -> Result<types::StateObject, errors::Error> {
413        let mut read_lock = self.ha_client.read().unwrap();
414        if read_lock.token.need_refresh() {
415            drop(read_lock);
416            let mut write_lock = self.ha_client.write().unwrap();
417            write_lock.refresh_oauth_token().await?;
418            read_lock = self.ha_client.read().unwrap();
419        }
420
421        let endpoint = format!("{}/api/states/{}", read_lock.instance_url, entity_id);
422        let mut request = reqwest::Client::new()
423            .post(endpoint.as_str())
424            .header(
425                "Authorization",
426                format!("Bearer {}", read_lock.token.as_string()?),
427            )
428            .header("content-type", "application/json");
429
430        drop(read_lock);
431
432        if let Some(data) = state_data {
433            request = request.json(&data);
434        }
435
436        let response = request.send().await?;
437
438        let resp_json: types::StateObject = response.json().await?;
439
440        Ok(resp_json)
441    }
442
443    pub async fn event_fire(
444        self,
445        event_type: String,
446        event_data: Option<impl serde::Serialize>,
447    ) -> Result<String, errors::Error> {
448        let mut read_lock = self.ha_client.read().unwrap();
449        if read_lock.token.need_refresh() {
450            drop(read_lock);
451            let mut write_lock = self.ha_client.write().unwrap();
452            write_lock.refresh_oauth_token().await?;
453            read_lock = self.ha_client.read().unwrap();
454        }
455
456        let endpoint = format!("{}/api/events/{}", read_lock.instance_url, event_type);
457        let mut request = reqwest::Client::new()
458            .post(endpoint.as_str())
459            .header(
460                "Authorization",
461                format!("Bearer {}", read_lock.token.as_string()?),
462            )
463            .header("content-type", "application/json");
464
465        drop(read_lock);
466
467        if let Some(data) = event_data {
468            request = request.json(&data);
469        }
470
471        let response = request.send().await?;
472
473        #[derive(Serialize, Deserialize, Debug)]
474        struct Response {
475            message: String,
476        }
477
478        let resp_json: Response = response.json().await?;
479
480        Ok(resp_json.message)
481    }
482
483    pub async fn service_call<T>(
484        self,
485        domain: String,
486        service: String,
487        service_data: Option<impl serde::Serialize>,
488    ) -> Result<Vec<types::StateObject>, errors::Error> {
489        let mut read_lock = self.ha_client.read().unwrap();
490        if read_lock.token.need_refresh() {
491            drop(read_lock);
492            let mut write_lock = self.ha_client.write().unwrap();
493            write_lock.refresh_oauth_token().await?;
494            read_lock = self.ha_client.read().unwrap();
495        }
496
497        let endpoint = format!(
498            "{}/api/services/{}/{}",
499            read_lock.instance_url, domain, service
500        );
501        let mut request = reqwest::Client::new()
502            .post(endpoint.as_str())
503            .header(
504                "Authorization",
505                format!("Bearer {}", read_lock.token.as_string()?),
506            )
507            .header("content-type", "application/json");
508
509        drop(read_lock);
510
511        if let Some(data) = service_data {
512            request = request.json(&data);
513        }
514
515        let response = request.send().await?;
516
517        let resp_json: Vec<types::StateObject> = response.json().await?;
518
519        Ok(resp_json)
520    }
521
522    pub async fn template_render(self, template: String) -> Result<String, errors::Error> {
523        let mut read_lock = self.ha_client.read().unwrap();
524        if read_lock.token.need_refresh() {
525            drop(read_lock);
526            let mut write_lock = self.ha_client.write().unwrap();
527            write_lock.refresh_oauth_token().await?;
528            read_lock = self.ha_client.read().unwrap();
529        }
530
531        let endpoint = format!("{}/api/template", read_lock.instance_url);
532
533        #[derive(Serialize, Deserialize, Debug)]
534        struct Template {
535            template: String,
536        }
537
538        let template_struct = Template { template };
539        let request = reqwest::Client::new()
540            .post(endpoint.as_str())
541            .header(
542                "Authorization",
543                format!("Bearer {}", read_lock.token.as_string()?),
544            )
545            .header("content-type", "application/json");
546
547        drop(read_lock);
548
549        let response = request.json(&template_struct).send().await?;
550
551        let resp: String = response.text().await?;
552
553        Ok(resp)
554    }
555
556    pub async fn check_config(self) -> Result<types::CheckConfig, errors::Error> {
557        let mut read_lock = self.ha_client.read().unwrap();
558        if read_lock.token.need_refresh() {
559            drop(read_lock);
560            let mut write_lock = self.ha_client.write().unwrap();
561            write_lock.refresh_oauth_token().await?;
562            read_lock = self.ha_client.read().unwrap();
563        }
564
565        let endpoint = format!("{}/api/config/core/check_config", read_lock.instance_url);
566        let response = reqwest::Client::new()
567            .post(endpoint.as_str())
568            .header(
569                "Authorization",
570                format!("Bearer {}", read_lock.token.as_string()?),
571            )
572            .header("content-type", "application/json")
573            .send()
574            .await?;
575
576        drop(read_lock);
577
578        let resp_json: types::CheckConfig = response.json().await?;
579
580        Ok(resp_json)
581    }
582}
583
584impl TryFrom<Weak<RwLock<crate::HomeAssistantAPI>>> for Rest {
585    type Error = errors::Error;
586
587    fn try_from(weak: Weak<RwLock<crate::HomeAssistantAPI>>) -> Result<Self, Self::Error> {
588        match weak.upgrade() {
589            Some(ptr) => Ok(Self { ha_client: ptr }),
590            None => Err(errors::Error::HaApi(String::from(
591                "Can't create Rest Client weak ptr returned none",
592            ))),
593        }
594    }
595}
596
597impl From<Arc<RwLock<crate::HomeAssistantAPI>>> for Rest {
598    fn from(ptr: Arc<RwLock<crate::HomeAssistantAPI>>) -> Self {
599        Self { ha_client: ptr }
600    }
601}